「NOIP 2023 模拟赛 20230711 B」过往未来

summarization

给定一个 n 个节点的树,定义 x1,x2,,xk 生成的子树为树中边数最少的包含 x1,x2,,xk 的连通块。

对所有可能的 x1,x2,,xk(1x1<x2<<xkn),求 x1,x2,,xk 生成的子树的大小(边数和)总和。

solution

考虑分别计算每一条边的贡献。

若这条边要产生贡献,当且仅当它的两边都有点被选中。若这条边深度较大的点为根的子树的大小为 x,整棵树的大小为 n

那么总的选点方案数为 Cnk,全选在子树中的方案为 Cxk,全选在子树外的方案为 Cnxk,则跨越这条边的方案数为 CnkCxkCnxk

code

CI N = 1e6, N2 = 2e6; const ll mod = 998244353; int n, k; ll inv[N + 5], invf[N + 5], sz[N + 5], ans = 0;
namespace graph {
	int nxt[N2 + 5], to[N2 + 5], hd[N + 5], cnt = 0;
	void A (int u, int v) {++ cnt; to[cnt] = v; nxt[cnt] = hd[u]; hd[u] = cnt;}
} using namespace graph;
ll Pow (ll x, ll p) {ll r = 1; for (; p; p >>= 1, x = x * x % mod) if (p & 1) r = r * x % mod; return r;}
void init () {
	RI i, j; inv[0] = inv[1] = 1; for (i = 2; i <= n; ++ i) inv[i] = inv[i - 1] * i % mod; invf[n] = Pow (inv[n], mod - 2);
	for (i = n - 1; i >= 0; -- i) invf[i] = invf[i + 1] * (i + 1) % mod;
}
ll C (int x, int y) {return inv[x] * invf[y] % mod * invf[x - y] % mod;} 
void dfs (int now, int fa) {
	RI i, j; sz[now] = 1; for (i = hd[now]; i; i = nxt[i]) {
		if (to[i] == fa) continue; dfs (to[i], now); sz[now] += sz[to[i]];
	} if (now != 1) ans = (ans - (k > sz[now] ? 0 : C (sz[now], k)) - (k > n - sz[now] ? 0 : C (n - sz[now], k)) + mod + mod) % mod;
}
int main () {
	RI i, j; for (Read (n, k), i = 1; i < n; ++ i) {int x, y; Read (x, y); A (x, y); A (y, x);} init (); ans = C (n, k) * (ll)(n - 1) % mod;
	dfs (1, 0); printf ("%lld\n", ans);
	return 0; 
}
posted @   ClapEcho233  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探
点击右上角即可分享
微信分享提示