题解 SP7363 TREESUM-Tree Sum/[国家集训队] Crash 的文明世界

Update on 2022.2.12:才发现这题就是[国家集训队] Crash 的文明世界,所以建议直接上洛谷做(似乎可以直接点分治??)。

题目链接

题意描述:

给定一棵 \(n\) 个点的树,对于每个点求出以它为根时的 \(\sum\limits_{i=1}^{n}{dep_i}^k\)
\(n\leq 50000,k\leq 20\)

看到 对于每个点,马上想到换根 \(dp\) ,先以 \(1\) 为根求出 \(dep_u\),设 \(dp_u\) 为以 \(u\) 为根的答案,则 $$dp_u=\sum\limits_{v\in Tree(u)}(dep_v-dep_u)^k+\sum\limits_{v\notin Tree(u)}(dep_u-dep_v)^k$$

先考虑计算前一部分:

看到 \(^k\) 想到二项式定理或第二类斯特林数,先用二项式定理推推:

\[\begin{aligned}\sum\limits_{v\in Tree(u)}(dep_v-dep_u)^k&=\sum\limits_{v\in Tree(u)}\sum\limits_{i=0}^{k}\binom{k}{i}\times {dep_v}^i\times (-dep_u)^{k-i}\end{aligned} \]

发现后面那个 \((-dep_u)^{k-i}\) 的系数拆不出来,无法把子树 \(\to\) 根的转移转化为儿子 \(\to\) 父亲的转移,只能放弃。

接下来用斯特林数推:

\[\begin{aligned}\sum\limits_{v\in Tree(u)}(dep_v-dep_u)^k&=\sum\limits_{v\in Tree(u)}\sum\limits_{i=0}^{dep_v-dep_u}{k\brace i}\times \binom{dep_v-dep_u}{i}\times i!\end{aligned} \]

当然,由于 \(i=0\)\(i>k\) 时没有意义,因此写成:

\[\begin{aligned}\sum\limits_{v\in Tree(u)}(dep_v-dep_u)^k&=\sum\limits_{v\in Tree(u)}\sum\limits_{i=1}^{k}{k\brace i}\times \binom{dep_v-dep_u}{i}\times i!\end{aligned} \]

斯特林数和阶乘可以直接算,因此只要考虑 \(\binom{dep_v-dep_u}{i}\) 就可以了。

发现根从 \(u\) 转移到 \(Son_u\) 时组合数变为 \(\binom{dep_v-dep_u-1}{i}\) ,可以想到杨辉三角的结论: \(\binom{n}{m}=\binom{n-1}{m}+\binom{n-1}{m-1}\) ,于是设 \(f_{u,i}=\sum\limits_{v\in Tree(u)}\binom{dep_v-dep_u}{i}\),这样列出转移为:

\[\begin{aligned}f_{u,i}&=\sum\limits_{v\in Tree(u)}\binom{dep_v-dep_u}{i}\\&=\sum\limits_{v\in Son(u)}\sum\limits_{w\in Tree(v)}\binom{dep_w-dep_v+1}{i}\\&=\sum\limits_{v\in Son(u)}\sum\limits_{w\in Tree(v)}\binom{dep_w-dep_v}{i}+\binom{dep_w-dep_v}{i-1}\\&=\sum\limits_{v\in Son(u)}f_{v,i}+f_{v,i-1}\end{aligned} \]

换根就是把儿子的 \(f_{v,1\sim k}\) 加上父亲的贡献,每遍历到一个点计算答案就可以了。

后一部分类似。

具体地:

\[f_{v,i}=f_{u,i}+f_{u,i-1}-2\times f_{v,i-1}-f_{v,i-2} \]

\[f_{v,1}=f_{u,1}+f_{u,0}-2\times f_{v,i-1} \]

\[f_{v,0}=f_{u,0} \]

注意这里要从 \(k\)\(1\) 修改,因为前面的修改会影响后面的修改。

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e15
#define N 100005
#define ls k<<1
#define rs k<<1|1
#define mid ((l+r)>>1)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define pii pair<int,int>
#define il inline
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)
using namespace std;
il int read(){
	int w=0,h=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')h=-h;ch=getchar();}
	while(ch>='0'&&ch<='9'){w=w*10+ch-'0';ch=getchar();}
	return w*h;
}
const int mod=1e9+7;
struct Edge{
	int next,to;
}edge[N<<1];
int T,n,K;
int head[N],num;
int S[N][25];
int Dep[N],Fac[N],F[N][25],Dp[N];
void Clear(){
	num=0;
	for(int i=1;i<=n;i++){
		Dp[i]=0;
		Dep[i]=0;
		head[i]=0;
		for(int j=0;j<=K;j++)
			F[i][j]=0;
	}
}
void add(int u,int v){
	edge[++num].next=head[u];
	edge[num].to=v;head[u]=num;
}
void Stirling(){
	Fac[0]=S[0][0]=1;
	for(int i=1;i<=K;i++){
		Fac[i]=Fac[i-1]*i%mod;
		for(int j=1;j<=K;j++)
			S[i][j]=(S[i-1][j-1]+j*S[i-1][j]%mod)%mod;
	}
}
void dfs1(int u,int fa){
	Dep[u]=Dep[fa]+1;
	F[u][0]=F[u][1]=1;
	for(int i=head[u];i;i=edge[i].next){
		int v=edge[i].to;
		if(v==fa)continue;
		dfs1(v,u);
		F[u][0]=(F[u][0]+F[v][0])%mod;
		for(int j=1;j<=K;j++)
			F[u][j]=(F[u][j]+F[v][j]+F[v][j-1])%mod;
	}
}
void dfs2(int u,int fa){
	for(int i=1;i<=K;i++)Dp[u]=(Dp[u]+S[K][i]*F[u][i]%mod*Fac[i]%mod)%mod;
	for(int i=head[u];i;i=edge[i].next){
		int v=edge[i].to;
		if(v==fa)continue;
		for(int j=K;j>=2;j--)
			F[v][j]=(F[u][j]+F[u][j-1]-(F[v][j-1]<<1)%mod+mod-F[v][j-2]+mod)%mod;
		F[v][1]=(F[u][1]+F[u][0]-(F[v][0]<<1)%mod+mod)%mod;
		F[v][0]=F[u][0];
		dfs2(v,u);
	}
}
signed main(){
	T=read();
	K=20;
	Stirling();
	while(T--){
		n=read();K=read();
		Clear();
		for(int i=2;i<=n;i++){
			int u=read()+1,v=read()+1;
			add(u,v);add(v,u);
		}
		dfs1(1,0);
		dfs2(1,1);
		for(int i=1;i<=n;i++)printf("%lld\n",Dp[i]);puts("");
	}
	return 0;
}

posted @ 2021-11-11 14:37  pidan007  阅读(31)  评论(0编辑  收藏  举报