P9132 [USACO23FEB] Watching Cowflix P 题解
如果有 \(C\) 个连通块,选取了 \(b\) 个点,答案就是 \(Ck + b\)。
所以 \(C = 1\) 时,答案最多是 \(k + n\)。
对于 \(C > 1\),如果答案比 \(k + n\) 优,则需要 \(Ck + b \le k + n\) 即 \(k\le \dfrac{n}{C-1}\)。
考虑根号分治,如果 \(k\le \sqrt n\),用暴力 DP,\(f_{i,0/1}\) 表示以 \(i\) 为根的子树,\(i\) 是否选取,最小代价,这一部分是 \(O(n\sqrt n)\)。
如果 \(k > \sqrt n\),则 \(C\le \sqrt n + 1\),所以定义 \(h_{i, j, 0/1}\) 表示以 \(i\) 为根的子树,当前分为了 \(j\) 个连通块,\(i\) 是否选取,最小点数,最后枚举有多少个连通块即可。
根据树形背包的复杂度分析,容量是 \(m < n\) 的背包,复杂度是 \(O(nm)\),所以这一部分是 \(O(n\sqrt n)\)。
证明:考虑 DFN 上两个子树的合并,他们在 DFN 上一定相邻,
钦定认为一次合并是把左子树的最靠右的 \(m\) 个和右子树最靠左的 \(m\) 个合并,所以只有在序列上距离不超过 \(2m-1\) 的点对之间,可能有贡献。
所以总复杂度是 \(O(n\sqrt n)\) 的。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
//#define int long long
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 2e5 + 10, INF = 1e9, B = 450;
bool Mst;
int n, dfn[N], pos[N], fa[N], sz[N], timestamp, f[N][2], res[N];
bool s[N];
vector<int> g[N], h[N][2];
void dfs(int u, int fat) {
sz[u] = 1, dfn[u] = ++ timestamp, pos[timestamp] = u, fa[u] = fat;
for(auto v : g[u]) if(v != fat) dfs(v, u), sz[u] += sz[v];
}
void cmin(int &a, int b) {
a = (a < b ? a : b);
}
bool Med;
signed main() {
// freopen("ex_data1.in", "r", stdin);
ios::sync_with_stdio(0), cin.tie(0);
cerr << abs(&Mst - &Med) / 1048576. << "Mb\n";
cin >> n;
for(int i = 1; i <= n; i ++) {
char ch; cin >> ch; s[i] = ch - '0';
}
for(int i = 1, a, b; i < n; i ++)
cin >> a >> b, g[a].push_back(b), g[b].push_back(a);
dfs(1, 0);
for(int k = 1; k <= min(B, n); k ++) {
for(int i = 1; i <= n; i ++) f[i][0] = 0, f[i][1] = 1;
for(int i = n, u; i; i --) {
u = pos[i];
if(s[u]) f[u][0] = INF;
f[fa[u]][1] += min(f[u][0], f[u][1]), f[fa[u]][0] += min(f[u][0], f[u][1] + k);
}
cout << min(f[1][0], f[1][1] + k) << '\n';
}
int m = n / B + 1;
for(int i = n, u; i; i --) {
u = pos[i], h[u][0].resize(min(m, sz[u]) + 2, INF), h[u][1].resize(min(m, sz[u]) + 2, INF);
if(!s[u]) h[u][0][0] = 0;
h[u][1][1] = 1;
int sum = 1;
for(auto v : g[u]) {
if(v != fa[u]) {
vector<int> tmp[2]; tmp[0] = h[u][0], tmp[1] = h[u][1];
h[u][0].assign(h[u][0].size(), INF), h[u][1].assign(h[u][1].size(), INF);
for(int i = 0; i <= min(m, sum); i ++) {
for(int j = 0; j < h[v][0].size() && i + j - 1 <= min(m, sz[u]); j ++) {
if(!s[u]) cmin(h[u][0][i + j], min(h[v][1][j], h[v][0][j]) + tmp[0][i]);
cmin(h[u][1][i + j], h[v][0][j] + tmp[1][i]);
cmin(h[u][1][i + j - 1], h[v][1][j] + tmp[1][i]);
}
}
sum += sz[v];
h[v][0] = vector<int>(), h[v][1] = vector<int>();
}
}
}
for(int i = 0; i <= min(m, n); i ++) res[i] = min(h[1][0][i], h[1][1][i]);
for(int k = B + 1; k <= n; k ++) {
int ans = INF;
for(int i = 0; i <= min(m, n / k + 1); i ++)
if(ans > i * k + res[i]) ans = i * k + res[i];
cout << ans << '\n';
}
return 0;
}

QwQ
浙公网安备 33010602011771号