結果
| 問題 |
No.3148 Min-Cost Destruction of Parentheses
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2025-05-16 21:59:37 |
| 言語 | C++14 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 76 ms / 4,000 ms |
| コード長 | 4,610 bytes |
| コンパイル時間 | 1,174 ms |
| コンパイル使用メモリ | 123,504 KB |
| 実行使用メモリ | 17,336 KB |
| 最終ジャッジ日時 | 2025-05-16 21:59:42 |
| 合計ジャッジ時間 | 3,828 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 31 |
コンパイルメッセージ
main.cpp: In function ‘int main()’:
main.cpp:138:10: warning: ignoring return value of ‘int scanf(const char*, ...)’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
138 | scanf("%s", S);
| ~~~~~^~~~~~~~~
main.cpp:141:12: warning: ignoring return value of ‘int scanf(const char*, ...)’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
141 | scanf("%lld", &A[u]);
| ~~~~~^~~~~~~~~~~~~~~
ソースコード
#include <cassert>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <bitset>
#include <chrono>
#include <complex>
#include <deque>
#include <functional>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
using Int = long long;
template <class T1, class T2> ostream &operator<<(ostream &os, const pair<T1, T2> &a) { return os << "(" << a.first << ", " << a.second << ")"; };
template <class T> ostream &operator<<(ostream &os, const vector<T> &as) { const int sz = as.size(); os << "["; for (int i = 0; i < sz; ++i) { if (i >= 256) { os << ", ..."; break; } if (i > 0) { os << ", "; } os << as[i]; } return os << "]"; }
template <class T> void pv(T a, T b) { for (T i = a; i != b; ++i) cerr << *i << " "; cerr << endl; }
template <class T> bool chmin(T &t, const T &f) { if (t > f) { t = f; return true; } return false; }
template <class T> bool chmax(T &t, const T &f) { if (t < f) { t = f; return true; } return false; }
#define COLOR(s) ("\x1b[" s "m")
// par: must represent a forest.
// The roots should point to -1 or n.
// T: monoid
// T() should return the identity.
// T::append(const T &t) should multiply t from right.
// T::operator<(const T &t) should represent the order to optimize.
// Small to large.
// It must be a weak order (for the possible products of ts).
template <class T>
struct ForestOptimalOrder {
int n;
bool isForest;
T total;
vector<int> us;
ForestOptimalOrder() : n(0), isForest(false), total() {}
ForestOptimalOrder(const vector<int> &par, vector<T> ts)
: n(par.size()), isForest(false), total() {
assert(n == static_cast<int>(ts.size()));
uf.assign(n + 1, -1);
std::priority_queue<Entry> que;
vector<int> tails(n + 1, n), nxt(n + 1, -1);
for (int u = 0; u < n; ++u) que.push(Entry{ts[u], u, tails[u] = u});
for (; !que.empty(); ) {
const int v = que.top().head, tail = que.top().tail;
que.pop();
if (tails[v] == tail) {
// v as early as possible ==> right after its parent
const int u = root((~par[v]) ? par[v] : n);
if (!connect(u, v)) return;
nxt[tails[u]] = v; tails[u] = tail;
if (u == n) {
total.append(ts[v]);
} else {
ts[u].append(ts[v]);
que.push(Entry{ts[u], u, tails[u]});
}
}
}
isForest = true;
us.resize(n);
for (int j = 0, u = n; j < n; ++j) us[j] = u = nxt[u];
}
struct Entry {
T t;
int head, tail;
// reversed order
bool operator<(const Entry &e) const { return (e.t < t); }
};
vector<int> uf;
int root(int u) {
return (uf[u] < 0) ? u : (uf[u] = root(uf[u]));
}
// root(u) becomes the parent
bool connect(int u, int v) {
u = root(u);
v = root(v);
if (u == v) return false;
uf[u] += uf[v];
uf[v] = u;
return true;
}
};
////////////////////////////////////////////////////////////////////////////////
struct Info {
// (weight, score) -> (weight + a, score + b * weight + c)
Int a, b, c;
Info() : a(0), b(0), c(0) {}
void append(const Info &t) {
b += t.b;
c += t.b * a + t.c;
a += t.a;
}
bool operator<(const Info &t) const {
return (t.b * a < b * t.a);
}
};
int N;
char S[200'010];
vector<Int> A;
vector<int> us, to;
vector<int> par;
void parse(int l, int r, int p) {
for (int x = l; x < r; x = to[x] + 1) {
const int u = us[x];
par[u] = p;
parse(x + 1, to[x], u);
}
}
int main() {
for (; ~scanf("%d", &N); ) {
scanf("%s", S);
A.resize(N);
for (int u = 0; u < N; ++u) {
scanf("%lld", &A[u]);
}
us.assign(2*N, -1);
to.assign(2*N, -1);
{
vector<int> stack;
int u = 0;
for (int x = 0; x < 2*N; ++x) {
if (S[x] == '(') {
stack.push_back(x);
us[x] = u++;
} else {
const int y = stack.back();
stack.pop_back();
to[y] = x;
to[x] = y;
}
}
}
par.assign(N, -2);
parse(0, 2*N, -1);
cerr<<"par = "<<par<<endl;
vector<Info> ts(N);
for (int u = 0; u < N; ++u) {
ts[u].a = 1;
ts[u].b = A[u];
ts[u].c = 0;
}
const ForestOptimalOrder<Info> foo(par, ts);
cerr<<"foo.us = "<<foo.us<<endl;
const Int ans = foo.total.b * 1 + foo.total.c;
printf("%lld\n", ans);
}
return 0;
}