APIO 2022-2024 做题笔记
太难了。(持续更新中……
目录
- APIO 2022-2024 做题笔记
- [APIO2023] 赛博乐园 / cyberland
- [APIO2024] 九月
[APIO2023] 赛博乐园 / cyberland
考虑倒过来转移,设 \(f_{u,j}\) 为从点 \(h\) 到点 \(u\),已经用了 \(j\) 次除以二了,那么接下来通过边的代价就变为了 \(\frac{w}{2^j}\),直接用 dijkstra 转移即可。
注意到 \(\frac{w}{2^j}\) 在 \(j\) 很大的时候几乎不计,所以只计算小于等于 \(70\) 的 \(j\) 即可。
时间复杂度 \(O(NK \log NK)\)。
ケロシの代码
const int N = 1e5 + 5;
const int K = 70;
const ll LNF = 2e18;
double pw[K + 1], d[N][K + 1];
bool vis[N][K + 1];
vector<PII> e[N];
double solve(int n, int m, int k, int ed, vector<int> x, vector<int> y, vector<int> c, vector<int> a
) {chmin(k, K);REP(i, n) e[i].clear();REP(i, m) {e[x[i]].push_back({y[i], c[i]});e[y[i]].push_back({x[i], c[i]});}pw[0] = 1;FOR(i, 1, K) pw[i] = pw[i - 1] / 2;priority_queue<pair<double, PII>, vector<pair<double, PII>>, greater<pair<double, PII>>> pq;REP(i, n) FOR(j, 0, K) d[i][j] = LNF;REP(i, n) FOR(j, 0, K) vis[i][j] = 0;d[ed][0] = 0;pq.push({0, {ed, 0}});while(! pq.empty()) {auto h = SE(pq.top());pq.pop();int u, j; tie(u, j) = h;if(vis[u][j]) continue;vis[u][j] = 1;for(auto E : e[u]) {int v, w; tie(v, w) = E;if(v == ed) continue;if(j == K) {if(d[v][K] > d[u][K]) {d[v][K] = d[u][K];pq.push({d[v][K], {v, K}});}continue;}if(a[v] == 0) {if(d[v][K] > d[u][j] + w * pw[j]) {d[v][K] = d[u][j] + w * pw[j];pq.push({d[v][K], {v, K}});}continue;}if(a[v] == 2 && j < k) {if(d[v][j + 1] > d[u][j] + w * pw[j]) {d[v][j + 1] = d[u][j] + w * pw[j];pq.push({d[v][j + 1], {v, j + 1}});}}if(d[v][j] > d[u][j] + w * pw[j]) {d[v][j] = d[u][j] + w * pw[j];pq.push({d[v][j], {v, j}});}}}double ans = LNF;FOR(i, 0, K) chmin(ans, d[0][i]);if(ans > LNF / 2) return - 1;else return ans;
}
[APIO2024] 九月
考虑对于单个序列,若出现儿子在祖先后面,则可以缩掉。
再考虑多个序列,每个点肯定在一个块里面,可以继续缩。
时间复杂度 \(O(NM \log N)\)。
ケロシの代码
const int N = 1e5 + 5;
vector<int> e[N];
int sz[N], dfn[N], cnt;
int lst[N];
struct SgT {int le[N << 2], ri[N << 2];int F[N << 2];void pushup(int u) {F[u] = max(F[u << 1], F[u << 1 | 1]);}void build(int u, int l, int r) {le[u] = l, ri[u] = r;if(l == r) {F[u] = 0;return;}int mid = l + r >> 1;build(u << 1, l, mid);build(u << 1 | 1, mid + 1, r);pushup(u);}void modify(int u, int p, int x) {if(le[u] == ri[u]) {F[u] = x;return;}int mid = le[u] + ri[u] >> 1;if(p <= mid) modify(u << 1, p, x);else modify(u << 1 | 1, p, x);pushup(u);}int query(int u, int l, int r) {if(l <= le[u] && ri[u] <= r) {return F[u];}int mid = le[u] + ri[u] >> 1;int res = 0;if(l <= mid) chmax(res, query(u << 1, l, r));if(mid < r) chmax(res, query(u << 1 | 1, l, r));return res;}
} t;
void dfs(int u) {dfn[u] = ++ cnt;sz[u] = 1;for(int v : e[u]) {dfs(v);sz[u] += sz[v];}
}
int solve(int n, int m, vector<int> p, vector<vector<int>> S) {cnt = 0;REP(i, n) e[i].clear();FOR(i, 1, n - 1) e[p[i]].push_back(i);dfs(0);vector<PII> f;REP(i, n - 1) f.push_back({i, i});for(auto A : S) {t.build(1, 1, n);ROF(i, n - 2, 0) {int u = A[i];int val = t.query(1, dfn[u], dfn[u] + sz[u] - 1);if(val > i) f.push_back({i, val});t.modify(1, dfn[u], i);}}REP(i, m) {if(i) REP(j, n - 1) {int l = j, r = lst[S[i][j]];if(l > r) swap(l, r);f.push_back({l, r});}REP(j, n - 1) lst[S[i][j]] = j;}sort(ALL(f));int ans = 0;int r = - 1;for(auto h : f) {if(FI(h) <= r) chmax(r, SE(h));else ans ++, r = SE(h);}return ans;
}