尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

题解:[COCI 2025/2026 #3] 国家 / Drzava

题解:[COCI 2025/2026 #3] 国家 / Drzava
📅 发布时间:2026/6/19 18:53:21

并且任意两座城市之间的最短路经过的道路数都小于 36。

前排提示:题面中这句话保证了给出的是一棵直径不超过 \(36\) 的树,但实际上这个题有一个完全不需要这个性质的 \(\mathcal O(n^2)\) 做法,如果你因为这个性质误入歧途可以重新思考一下。

\(k\le 2\) 的情况时平凡的,下面只讨论 \(k\ge 3\) 的情况。

考虑先不管首都在哪个点,设次级城市的点集为 \(S(|S|\ge 2)\)。如果 \(\exist x,y,z\in S\),满足 \(y\) 在 \(x\) 到 \(z\) 的路径上,则这个 \(S\) 一定不合法。如果 \(|S|=2\) 且 \(S\) 中两个点相邻,此时也找不到合法的首都。此外,可以说明一定存在一个点 \(x\),使得 \(x\) 可以作为首都,也就是将 \(x\) 设为树根时 \(S\) 中任意两点没有祖先后代关系。证明考虑以 \(1\) 为根的情况下 \(S\) 的形态,有两种情况:

  1. 如果此时 \(S\) 中任意两点没有祖先后代关系,则 \(1\) 就是合法的 \(x\);
  2. 否则,设点 \(y\in S\),\(y\) 的一个子节点为 \(x\),且 \(x\) 的子树中有 \(S\) 中的点。此时可以发现,由于 \(S\) 中任意两点路径不能经过 \(y\),所以 \(S\) 中其它的点都在 \(x\) 子树中且这些点之间没有祖先后代关系。同时由假设 \(x\notin S\),所以这就是一个可以作为首都的 \(x\)。

此时,任何一个不在 \(S\) 中某一点子树中的 \(y\) 也可做为首都(等价的表述是 \(x\) 到 \(y\) 的路径上没有 \(S\) 中的点,或者删除 \(S\) 中的点后 \(x\) 和 \(y\) 仍然连通),即可作为首都的点的数量为 \(n-\sum_{i\in S}sz_i\)。注意这里的 \(sz_i\) 指的是以 \(x\) 为根时 \(i\) 的子树大小,同时将 \(x\) 换成任意一个可以作为首都的 \(y\) 不会改变 \(S\) 中的点的 \(sz\)。

至此,dp 的状态设计和转移设计都已经有了。在以 \(1\) 为根的情况下,设 \(g_{x,i}\) 表示 \(x\) 的子树中选了 \(i\) 个点到 \(S\) 中,且它们都没有祖先后代关系,\(f_{x,i}\) 表示所有这些方案中 \(\sum sz_i\) 的和,在这种情况下 \(sz_i=siz_i\),也就是以首都为根时的子树大小等于以 \(1\) 为根时的子树大小。转移只需要考虑三种情况:

  1. 合并 \(x\) 的子树;
  2. 将 \(x\) 选入 \(S\) 中,且 \(x\) 的子树中没有其它 \(S\) 中的点;
  3. 将 \(x\) 选入 \(S\) 中,且 \(x\) 的子树中有其它的点。

其中第一种和第二种都是常规的树形背包。对于第三种,此时 \(S\) 中所有点都已经确定了。枚举 \(y,i\),其中 \(y\) 为 \(x\) 的子节点,表示 \(S\) 中其它的 \(i\) 个点都在 \(y\) 子树中。此时点 \(y\) 可以作为首都,且对应的 \(sz_x=n-siz_y\),所以计算 \(G=g_{y,i},F=f_{y,i}+g_{y,i}\times(n-siz_y)\),将 \(n\times G-F\) 计入 \(ans_{i+2}\) 即可(\(i+2\) 是加上点 \(x\) 和首都)。

最后考虑 \(S\) 中任意两点没有祖先后代关系的情况,此时 \(1\) 可以作为首都,故对于每个 \(i\),将 \(n\times g_{1,i}-f_{1,i}\) 计入 \(ans_{i+1}\) 即可。

前两种转移由树形背包结论复杂度为 \(\mathcal O(n^2)\),第三种复杂度为 \((y,i)\) 的数量也是 \(\mathcal O(n^2)\),总复杂度 \(\mathcal O(n^2)\)。

#include <bits/stdc++.h>
typedef long long LL;
typedef __int128 LLL;
typedef unsigned long long ULL;
typedef std::pair<int, int> pii;
typedef long double RN;
#define fi first
#define se second
#define MP std::make_pair
#define EB emplace_backLL read()
{LL s = 0; int f = 1, c = getchar();for (; !isdigit(c); c = getchar()) f ^= (c == '-');for (; isdigit(c); c = getchar()) s = s * 10 + (c ^ 48);return f ? s : -s;
}
template<typename T> 
void write(T x, char end = '\n')
{if (x < 0) x = -x, putchar('-');static int d[100], cur = 0;do { d[++cur] = x % 10; } while (x /= 10);while (cur) putchar(48 ^ d[cur--]);putchar(end);
}
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fll;
template<typename T> void Fmin(T &x, T y){ if (y < x) x = y; }
template<typename T> void Fmax(T &x, T y){ if (x < y) x = y; }
const int MOD = 1e9 + 7;
int fplus(int x, int y){ if ((x += y) >= MOD) return x - MOD; return x;  }
int fminus(int x, int y){ if ((x -= y) < 0) return x + MOD; return x; }
void Fplus(int &x, int y){ if ((x += y) >= MOD) x -= MOD; }
void Fminus(int &x, int y){ if ((x -= y) < 0) x += MOD; }
int fpow(int x, int y = MOD - 2)
{int res = 1;for (; y; y >>= 1, x = (LL)x * x % MOD)if (y & 1) res = (LL)res * x % MOD;return res; 
}
const int MAXN = 3005;
int n, siz[MAXN];
int f[MAXN][MAXN], g[MAXN][MAXN];
int ans[MAXN];
std::vector<int> e[MAXN];
void dfs(int x, int fat)
{for (int y : e[x]) if (y != fat) dfs(y, x);f[x][0] = 0, g[x][0] = 1;static int tf[MAXN], tg[MAXN], sf[MAXN], sg[MAXN];memset(sf, 0, n << 2);memset(sg, 0, n << 2);for (int y : e[x]) if (y != fat){memcpy(tf, f[x], (siz[x] + 1) << 2), memset(f[x], 0, (siz[x] + 1) << 2);memcpy(tg, g[x], (siz[x] + 1) << 2), memset(g[x], 0, (siz[x] + 1) << 2);for (int i = 0; i <= siz[x]; i++)for (int j = 0; j <= siz[y]; j++){Fplus(g[x][i + j], (LL)tg[i] * g[y][j] % MOD);Fplus(f[x][i + j], ((LL)tg[i] * f[y][j] + (LL)tf[i] * g[y][j]) % MOD);}siz[x] += siz[y];for (int i = 1; i <= siz[y]; i++){int G = g[y][i], F = (f[y][i] + (LL)G * (n - siz[y])) % MOD;int res = fminus((LL)n * G % MOD, F);Fplus(ans[i + 2], res);}}Fplus(ans[2], siz[x]);++siz[x], Fplus(f[x][1], siz[x]), Fplus(g[x][1], 1);// printf("---------- %d ------------\n", x);// for (int i = 0; i <= siz[x]; i++) printf("%d%c", f[x][i], " \n"[i == siz[x]]);// for (int i = 0; i <= siz[x]; i++) printf("%d%c", g[x][i], " \n"[i == siz[x]]);// printf("--------------------------\n");
}
int main()
{n = read();for (int i = 1; i < n; i++){int u = read(), v = read();e[u].push_back(v), e[v].push_back(u);}dfs(1, 0);for (int i = 0; i < n; i++)Fplus(ans[i + 1], fminus((LL)n * g[1][i] % MOD, f[1][i]));for (int i = 1; i <= n; i++) write(ans[i], " \n"[i == n]);return 0;
}

相关新闻

  • vue+springboot基于java的短剧推荐系统设计与实现_c0ql52z2_zl028--论文
  • Kotaemon中的超时控制与请求重试机制详解
  • HarmonyOS 5.0 WiFi连接调试工具

最新新闻

  • CANN/ge GetOutputsSize API文档
  • 2026年6月最新万国中国官方售后服务电话客服网点地址一览 - 亨得利官方服务中心
  • 我热爱上班 !哈哈哈,已封
  • 2026 年郑州市厨卫屋顶防水修缮三家横向测评:吉修匠 99.8 分稳居榜首 - 吉修匠
  • 孩子近视防控全方案技术解析:配镜与干预双维度 - 起跑123
  • Gemma-3-12B-IT WebUI安全加固:HTTPS、IP白名单与频率限制实战

日新闻

  • 信任的进化:技术实现详解——如何用JavaScript构建博弈论模拟器
  • Terrakube自定义工作流:如何集成OPA、Infracost等工具扩展IaC能力
  • grunt-concurrent快速入门:5分钟学会并行运行Grunt任务

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号