1 条题解
-
0
自动搬运
来自洛谷,原作者为

Sol1
博客:sol1.netlify.app搬运于
2025-08-24 22:45:19,当前版本为作者最后更新于2023-05-23 22:27:08,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
upd. 修个笔误。
数据随机自然是乱搞。
考虑一个暴力 dp: 表示 子树,断了 条边,根所在连通块的 的和是 ,最小的连通块平方和。
对于边 ,转移是:
- (不断 边)
- (断 边)
复杂度 ,显然过不了。
考虑剪枝,对于 ,如果 ,那么 显然没用。
于是我们对每一个 开个 vector 存所有有用的 ,每次暴力枚举两个 转移,转移完暴力对所有 vector 按 排序再暴力删掉所有没用的点。
然后这个算法就直接以最大点不到半秒的优异表现通过了这道题!
复杂度我不会严格分析,不过感性理解的话,假定 dp 数组在树和点权都均匀随机的情况下足够均匀随机,那么根据前缀最大值个数期望(也就是笛卡尔树深度期望),复杂度可以分析为 。
const int N = 305; struct Edge { int to, nxt; Edge() { nxt = -1; } }; int n, hd[N], siz[N], pnt; long long a[N]; Edge e[N << 1]; vector <pair <long long, long long> > dp[N][N], tmp[N]; inline void AddEdge(int u, int v) { e[++pnt].to = v; e[pnt].nxt = hd[u]; hd[u] = pnt; } inline void Read() { n = qread(); for (int i = 1;i <= n;i++) a[i] = qread(); for (int i = 1;i < n;i++) { int u = qread(), v = qread(); AddEdge(u, v); AddEdge(v, u); } } inline void Dfs(int u, int fa) { siz[u] = 1; for (int i = 0;i <= n;i++) dp[u][i].clear(); dp[u][0].push_back(make_pair(a[u], a[u] * a[u])); for (int i = hd[u];~i;i = e[i].nxt) { int v = e[i].to; if (v != fa) { Dfs(v, u); for (int i = 0;i <= siz[v];i++) { for (int j = 0;j <= siz[u];j++) { for (auto x : dp[v][i]) { for (auto y : dp[u][j]) { tmp[i + j].push_back(make_pair(x.first + y.first, x.second + y.second + 2 * x.first * y.first)); tmp[i + j + 1].push_back(make_pair(y.first, x.second + y.second)); } } } } siz[u] += siz[v]; for (int i = 0;i <= siz[u];i++) { dp[u][i].clear(); sort(tmp[i].begin(), tmp[i].end()); long long mnv = 0x3f3f3f3f3f3f3f3f; for (int j = 0;j < tmp[i].size();j++) { if (tmp[i][j].second < mnv) { mnv = tmp[i][j].second; dp[u][i].push_back(tmp[i][j]); } } tmp[i].clear(); } } } }
- 1
信息
- ID
- 8401
- 时间
- 3500ms
- 内存
- 256MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者