Crash的文明世界

description

题目链接

给出一个n 个点的树,对于每个点u

S(u)=i=1ndis(i,u)k

data range

n50000,k150

solution

先来推式子

S(u)=i=1ndis(i,u)k=i=1nj=0k{kj}dis(i,u)j_=j=0kj!{kj}i=1n(dis(i,u)j)

因此只需对每个点u 和次数j 求出i=1n(dis(i,u)j) 就可以了

fu,j=i=1n(dis(i,u)j) ,upu,j=iu(dis(i,u)j) ,downu,j=iu(dis(i,u)j) 显然fu,j=upu,j+downu,j

注意组合数有很好的性质

(nm)=(n1m)+(n1m1)

先考虑downu,j (简单些)

downu,j=iu(dis(i,u)j)=[j=0]+iu((dis(i,u)1j)+(dis(i,u)1j1))=[j=0]+iu((dis(i,v)j)+(dis(i,v)j1))=[j=0]+iu(downv,j+downv,j1)

再考虑upu,j

upu,j=iu(dis(i,u)j)=ifau(dis(i,fau)+1j)+ifau(dis(i,fau)+1j)iu(dis(i,u)+2j)=upfau,j+upfau,j1+downfau,j+downfau,j1downu,j2downu,j1downu,j2

注意边界上需要特殊处理

这类题目只是外面套了个斯特林数的外壳,本质还是dp 之类的传统东西

普通幂的差分十分困难(即便预处理组合数也需要O(k)),而斯特林数将普通幂转为下降幂使得其差分变得简单(O(1))

time complexity

O(nk)

code

#include<bits/stdc++.h>
using namespace std;
const int N=5e4+5,K=155,mod=1e4+7;
int f[N][K],s2[K][K],n,k;
int tot,fi[N],ne[N<<1],to[N<<1];
inline int read()
{
	int s=0,w=1; char ch=getchar();
	for(;!isdigit(ch);ch=getchar())if(ch=='-')w=-1;
	for(;isdigit(ch);ch=getchar())s=(s<<1)+(s<<3)+(ch^48);
	return s*w;
}
inline void adde(int x,int y){ne[++tot]=fi[x],fi[x]=tot,to[tot]=y;}
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
inline void pre()
{
	s2[0][0]=1;
	for(int i=1;i<=k;++i)
		for(int j=1;j<=k;++j)
			s2[i][j]=add(s2[i-1][j-1],s2[i-1][j]*j%mod);
}
int down[N][K],up[N][K];
void dfs1(int u,int f)
{
	down[u][0]=1;
	for(int i=fi[u];i;i=ne[i])
	{
		int v=to[i];
		if(v==f)continue;
		dfs1(v,u);
		down[u][0]=add(down[u][0],down[v][0]);
		for(int j=1;j<=k;++j)
			down[u][j]=add(down[u][j],add(down[v][j],down[v][j-1]));
	}
}
void dfs2(int u,int f)
{
	int now[K];
	now[0]=add(up[u][0],down[u][0]);
	for(int j=1;j<=k;++j)
		now[j]=(up[u][j]+up[u][j-1]+down[u][j]+down[u][j-1])%mod;
	for(int i=fi[u];i;i=ne[i])
	{
		int v=to[i];
		if(v==f)continue;
		up[v][0]=dec(now[0],down[v][0]);
		up[v][1]=dec(now[1],add(down[v][1],add(down[v][0],down[v][0])));
		for(int j=2;j<=k;++j)
			up[v][j]=dec(now[j],add(down[v][j],add(2*down[v][j-1]%mod,down[v][j-2])));
		dfs2(v,u);
	}
}
int main()
{
	n=read(),k=read();
	for(int i=1,u,v;i<n;++i)
	{
		u=read(),v=read();
		adde(u,v),adde(v,u);
	}
	pre();dfs1(1,0);dfs2(1,0);
	for(int i=1;i<=n;++i)
	{
		int ans=0,fac=1;
		for(int j=0;j<=k;++j,fac=fac*j%mod)
			ans=add(ans,fac*s2[k][j]%mod*add(up[i][j],down[i][j])%mod);
		printf("%d\n",ans);
	}
	return 0;
}
posted @   BILL666  阅读(69)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示