voidsolve(void){ cin >> n >> c >> d; for (int i = 1; i <= n; ++i) cin >> a[i]; sort(a + 1, a + n + 1); int m = unique(a + 1, a + n + 1) - (a + 1); i64 ans = 1ll * m * c + d; for (int i = 1; i <= m; ++i) ans = min(ans, 1ll * (a[i] - i) * d + 1ll * (m - i) * c); cout << ans + 1ll * c * (n - m) << "\n"; }
intmain(void){ ios::sync_with_stdio(0); cin.tie(0); int T = 1; cin >> T; while (T--) solve(); return0; }
设 D(x) 表示 x 为出生点可以走到的点集。假设 u∈D(x),D(y),而且 ∣D(x)∣<∣D(y)∣,那么 y 能够走到 x 但是 x 不能走到 y。以中间那个阻止 x 继续前进的点分割,y 必然有不小于 x 的规模,因此 2∣D(x)∣≤∣D(y)∣。因此任意一个点最多只会被计算 logn 个有效出生点计算到。证得 O(nlog2n)。
boolwork(int x){ #define pii pair<int, int> priority_queue<pii, vector<pii>, greater<pii>> q; q.emplace(0, x); int cnt = 0; while (!q.empty()) { int u = q.top().second; q.pop(); if (vis[u] == x) continue; vis[u] = x; ++cnt; if (a[u] >= cnt) return0; for (int v : G[u]) if (vis[v] != x) q.emplace(a[v], v); } return cnt == n; }
voidsolve(void){ cin >> n >> m; for (int i = 1; i <= n; ++i) vector<int>().swap(G[i]), cin >> a[i]; while (m--) { int u, v; cin >> u >> v; G[u].emplace_back(v); G[v].emplace_back(u); } memset(vis, 0, sizeof vis); for (int i = 1; i <= n; ++i) if (a[i] == 0 && vis[i] == 0) if (work(i)) return cout << "YES\n", void(); cout << "NO\n"; }
intmain(void){ ios::sync_with_stdio(0); cin.tie(0); int T = 1; cin >> T; while (T--) solve(); return0; }
G. The Maximum Prefix
直接做怎么做?设 fi 表示前 i 个数,当前前缀和为 j,最大前缀和为 k,然后刷表转移对于每个状态是 O(1) 的,炸了。
#include<bits/stdc++.h> usingnamespace std; typedeflonglong i64; constint P = 1000000007; constint N = 5e3 + 5;
inlineintpoww(int a, int b){ int r = 1; for (; b; b >>= 1, a = 1ll * a * a % P) if (b & 1) r = 1ll * r * a % P; return r; } inlineintinv(int x){ returnpoww(x, P - 2); } inlinevoidadd(int &x, i64 k){ x = (x + k) % P; }
int n; int p[N]; int f[N][N];
voidsolve(void){ cin >> n; for (int i = 1; i <= n; ++i) { int x, y; cin >> x >> y; p[i] = 1ll * x * inv(y) % P; } for (int i = 0; i <= n + 2; ++i) for (int j = 0; j <= n + 2; ++j) f[i][j] = 0; for (int i = 0; i <= n; ++i) cin >> f[0][i]; for (int i = 0; i < n; ++i) for (int j = 0; j <= n; ++j) if (f[i][j]) { // i + 1 位置填 1 if (j) add(f[i + 1][j - 1], 1ll * p[i + 1] * f[i][j]);
// i + 1 位置填 -1 add(f[i + 1][j + 1], 1ll * (1 + P - p[i + 1]) * f[i][j]); if (j == 0) add(f[i + 1][0], 1ll * (1 + P - p[i + 1]) * f[i][j]); } for (int i = 1; i <= n; ++i) cout << f[i][0] << " \n"[i == n]; }
intmain(void){ ios::sync_with_stdio(0); cin.tie(0); int T = 1; cin >> T; while (T--) solve(); return0; }