「BZOJ 2159」Crash的文明世界

给定一棵 nn 个节点的树,对于每个节点,计算出:S(i)=j=1ndist(i,j)k(mod10007)S(i)=\sum _{j=1}^ndist(i,j)^k \pmod {10007}。其中 dist(i,j)dist(i, j) 表示第 ii 个节点到第 jj 个节点路径上的边数,kk 为一个常数且为正整数。

Constraints

n50000n \leq 50000k150k \leq 150

Solution

用结论来化简式子:xn=i=1nS(n,i)F(x,i)x^n=\sum _{i=1}^n S(n,i)\cdot F(x,i)

S(n,i)S(n,i)为第二类斯特林数,F(x,i)=x!(xi)!F(x,i)=\frac{x!}{(x-i)!}

可得:

ans(i)=j=1ndist(i,j)m=j=1nk=1mS(m,k)F(dist(i,j),k)=k=1mS(m,k)j=1nF(dist(i,j),k)=k=1mS(m,k)k!j=1nC(dist(i,j),k)\begin{aligned} ans(i)&=\sum _{j=1}^ndist(i,j)^m\\ &=\sum_{j=1}^{n}\sum_{k=1}^{m}S(m,k)\cdot F(dist(i,j),k)\\ &=\sum_{k=1}^{m}S(m,k)\sum_{j=1}^{n} F(dist(i,j),k)\\ &=\sum_{k=1}^{m}S(m,k)\cdot k!\cdot \sum_{j=1}^{n} C(dist(i,j),k) \end{aligned}

根据组合数递推公式:C(n,m)=C(n1,m)+C(n1,m1)C(n,m)=C(n-1,m)+C(n-1,m-1) 就可以很方便的对后面的部分进行树形 dp 了。

具体地,令 up(x,i)up(x,i) 为不在 xx 的子树中的部分的贡献,令 dn(x,i)dn(x,i)xx 的子树的贡献。特别的,dn(x,0)=1dn(x,0)=1

详见代码。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include<cstdio>
#include<algorithm>
#include<cstring>
#define LL long long
using namespace std;
const int N=5e4+5;
const int M=155;
const int mod=1e4+7;
int n,m,u,v,cnt,ans,tmp;
int first[N],fac[M],s[M][M];
int up[N][M],dn[N][M];
struct edge{int to,next;}e[N*2];
int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
void ins(int u,int v){e[++cnt]=(edge){v,first[u]};first[u]=cnt;}
void Mod(int& a,int b){a+=b;if(a>=mod)a-=mod;}
void dfs1(int x,int fa)
{
dn[x][0]=1;
for(int i=first[x];i;i=e[i].next)
{
int to=e[i].to;
if(to==fa)continue;
dfs1(to,x);
Mod(dn[x][0],dn[to][0]);
for(int j=1;j<=m;j++)
Mod(dn[x][j],(dn[to][j]+dn[to][j-1])%mod);
}
}
void dfs2(int x,int fa)
{
if(fa!=-1)
{
up[x][0]=n-dn[x][0];
for(int i=1;i<=m;i++)
{
Mod(up[x][i],(up[fa][i]+up[fa][i-1])%mod);
Mod(up[x][i],(dn[fa][i]+dn[fa][i-1])%mod);
Mod(up[x][i],(2*mod-dn[x][i]-dn[x][i-1])%mod);
Mod(up[x][i],(mod-dn[x][i-1])%mod);
if(i!=1)Mod(up[x][i],(mod-dn[x][i-2])%mod);
}
}
for(int i=first[x];i;i=e[i].next)
if(e[i].to!=fa)dfs2(e[i].to,x);
}
int main()
{
int L,now,A,B,Q;
n=read();m=read();L=read();
now=read();A=read();B=read();Q=read();
for(int i=1;i<n;i++)
{
now=(now*A+B)%Q;
tmp=i<L?i:L;
u=i-now%tmp;v=i+1;
ins(u,v);ins(v,u);
}
// n=read();m=read();
// for(int i=1;i<n;i++)
// {
// u=read();v=read();
// ins(u,v);ins(v,u);
// }
fac[0]=s[0][0]=1;
for(int i=1;i<=m;i++)
{
fac[i]=fac[i-1]*i%mod;
for(int j=1;j<=i;j++)
s[i][j]=(s[i-1][j]*j+s[i-1][j-1])%mod;
}
dfs1(1,-1);dfs2(1,-1);
for(int i=1;i<=n;i++)
{
ans=0;
for(int j=1;j<=m;j++)
Mod(ans,s[m][j]*fac[j]%mod*(up[i][j]+dn[i][j])%mod);
printf("%d\n",ans);
}
return 0;
}