結果
| 問題 |
No.3148 Min-Cost Destruction of Parentheses
|
| コンテスト | |
| ユーザー |
pockyny
|
| 提出日時 | 2025-06-02 02:13:01 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 84 ms / 4,000 ms |
| コード長 | 3,869 bytes |
| コンパイル時間 | 1,604 ms |
| コンパイル使用メモリ | 92,504 KB |
| 実行使用メモリ | 15,348 KB |
| 最終ジャッジ日時 | 2025-06-02 02:13:06 |
| 合計ジャッジ時間 | 4,578 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 31 |
ソースコード
#include <iostream>
#include <vector>
using namespace std;
struct UF{
vector<int> par,sz;
// 連結成分の親
vector<int> cp_par;
vector<vector<int>> mergeTree;
UF(int n, bool useMergeTree = false){
sz.resize(n); par.resize(n); cp_par.resize(n);
for(int i=0;i<n;i++) sz[i] = 1, par[i] = i,cp_par[i] = i;
if(useMergeTree){
sz.resize(2*n); par.resize(2*n);
for(int i=n;i<2*n;i++) sz[i] = 1, par[i] = i;
mergeTree.resize(2*n);
}
}
int find(int x){
if(par[x]==x) return x;
return par[x] = find(par[x]);
}
void unite(int x,int y){
x = find(x); y = find(y);
if(x==y) return;
if(sz[x]>sz[y]) swap(x,y);
sz[y] += sz[x];
par[x] = y;
cp_par[y] = same(cp_par[y],y) ? cp_par[x] : cp_par[y];
}
bool same(int x,int y){return find(x)==find(y);}
void merge(int child,int parent){
//parentが親,merge過程を表す木などで使用
child = find(child); parent = find(parent);
if(child==parent) return;
mergeTree[parent].push_back(child);
sz[parent] += sz[child];
par[child] = parent;
}
};
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
typedef pair<pll,pll> pllll;
const int SZ = 200000;
// 問題ごとに必要なものを実装
ll val[SZ + 10],cnt[SZ + 10],ans[SZ + 10];
struct Cmp{
bool operator()(const pllll &l,const pllll &r){
// cout << l.first.first << "/" << l.first.second << "," << r.first.first << "/" << r.first.second << endl;
return l.first.first * r.first.second < l.first.second * r.first.first;
}
};
void merge(int x,int y){
}
// 01OnTreeを解く
// input: p,a. pは根を0として、0-nの親の配列 (p[0] = -1;)
// output 根から順にtopological順序で、0-nを割りふってΣi*a[i]の最小化
ll TreeTopoMin(vector<ll> &p, vector<ll> &a){
int i,n = p.size();
UF uf(n);
for(i=1;i<n;i++) uf.cp_par[i] = p[i];
for(i=1;i<n;i++) val[i] = a[i],cnt[i] = 1;
val[0] = 0; cnt[0] = 1;
priority_queue<pllll,vector<pllll>,Cmp> que;
int t = 0;
// queに入れたものの有効無効の判定に使う
vector<ll> tm_stamp(n);
auto custom_push = [&](int id){
que.push({{val[id],cnt[id]},{uf.find(id),t}});
tm_stamp[uf.find(id)] = t;
t++;
};
for(i=1;i<n;i++) custom_push(i);
while(que.size()){
auto [x,y] = que.top();
que.pop();
auto [v,c] = x;
auto [id,stamp] = y;
// queの中で有効 = 代表元かつ、stampが最新
// 他の物によって更新されると、代表が変わるか、stampの更新が起きる
if(uf.find(id)!=id || tm_stamp[id]!=stamp) continue;
// if(uf.find(id)!=id || val[id]!=v || cnt[id]!=c) continue;
// cout << id << " " << tm_stamp[id] << " " << stamp << " " << t << " " << v << " " << c << endl;
int pa = uf.find(uf.cp_par[id]);
ll nv = val[pa] + v,nc = cnt[pa] + c;
ll nans = ans[pa] + ans[id] + cnt[pa]*v;
uf.unite(id,pa);
int n_id = uf.find(id);
val[n_id] = nv; cnt[n_id] = nc; ans[n_id] = nans;
if(!uf.same(0,n_id)){
custom_push(n_id);
}
// for(i=0;i<=n;i++) cout << "{" << val[i] << "," << cnt[i] << "," << ans[i] << "} ";
// cout << "\n";
}
return ans[uf.find(0)];
}
int main(){
int i,n; cin >> n;
string s; cin >> s;
vector<ll> p(n + 1),a(n + 1);
for(i=1;i<=n;i++) cin >> a[i];
int now = 0,mx = 0;
p[0] = -1;
for(char c:s){
if(c=='('){
mx++;
p[mx] = now;
now = mx;
}else{
now = p[now];
}
}
cout << TreeTopoMin(p,a) << "\n";
}
pockyny