Crash的文明世界
description
给出一个nn 个点的树,对于每个点uu 求
S(u)=n∑i=1dis(i,u)kS(u)=n∑i=1dis(i,u)k
data range
n≤50000,k≤150n≤50000,k≤150
solution
先来推式子
S(u)=n∑i=1dis(i,u)k=n∑i=1k∑j=0{kj}dis(i,u)j_=k∑j=0j!{kj}n∑i=1(dis(i,u)j)S(u)=n∑i=1dis(i,u)k=n∑i=1k∑j=0{kj}dis(i,u)j–=k∑j=0j!{kj}n∑i=1(dis(i,u)j)
因此只需对每个点uu 和次数jj 求出∑ni=1(dis(i,u)j)∑ni=1(dis(i,u)j) 就可以了
记fu,j=∑ni=1(dis(i,u)j)fu,j=∑ni=1(dis(i,u)j) ,upu,j=∑i∉u(dis(i,u)j)upu,j=∑i∉u(dis(i,u)j) ,downu,j=∑i∈u(dis(i,u)j)downu,j=∑i∈u(dis(i,u)j) 显然fu,j=upu,j+downu,jfu,j=upu,j+downu,j
注意组合数有很好的性质
(nm)=(n−1m)+(n−1m−1)(nm)=(n−1m)+(n−1m−1)
先考虑downu,jdownu,j (简单些)
downu,j=∑i∈u(dis(i,u)j)=[j=0]+∑i∈u((dis(i,u)−1j)+(dis(i,u)−1j−1))=[j=0]+∑i∈u((dis(i,v)j)+(dis(i,v)j−1))=[j=0]+∑i∈u(downv,j+downv,j−1)downu,j=∑i∈u(dis(i,u)j)=[j=0]+∑i∈u((dis(i,u)−1j)+(dis(i,u)−1j−1))=[j=0]+∑i∈u((dis(i,v)j)+(dis(i,v)j−1))=[j=0]+∑i∈u(downv,j+downv,j−1)
再考虑upu,jupu,j
upu,j=∑i∉u(dis(i,u)j)=∑i∉fau(dis(i,fau)+1j)+∑i∈fau(dis(i,fau)+1j)−∑i∈u(dis(i,u)+2j)=upfau,j+upfau,j−1+downfau,j+downfau,j−1−downu,j−2downu,j−1−downu,j−2upu,j=∑i∉u(dis(i,u)j)=∑i∉fau(dis(i,fau)+1j)+∑i∈fau(dis(i,fau)+1j)−∑i∈u(dis(i,u)+2j)=upfau,j+upfau,j−1+downfau,j+downfau,j−1−downu,j−2downu,j−1−downu,j−2
注意边界上需要特殊处理
这类题目只是外面套了个斯特林数的外壳,本质还是dpdp 之类的传统东西
普通幂的差分十分困难(即便预处理组合数也需要O(k)O(k)),而斯特林数将普通幂转为下降幂使得其差分变得简单(O(1)O(1))
time complexity
O(nk)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;
}
NO PAIN NO GAIN
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何调试 malloc 的底层源码
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端