题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2159
题目分析:先说一下部分分怎么拿。
20% 20 % :直接以每个点为根DFS一遍,求出其它点的深度。预处理 1k 1 k ~ nk n k 统计答案。时间复杂度 O(n2+nk) O ( n 2 + n k ) 。
50% 50 % :令 S[node][d]=∑u∈nodedis(node,u)d S [ n o d e ] [ d ] = ∑ u ∈ n o d e d i s ( n o d e , u ) d 。当计算node父亲节点fa的S值时,显然有:
第一遍DFS完之后,再用一次DFS计算node的祖先对node的贡献。这个套路很常见,就不再多说了。时间复杂度是 O(nk2) O ( n k 2 ) 。
100% 100 % :发现计算S[fa][d]是个卷积的形式,所以用NTT优化
上面的方法虽然时间是 O(nklog(k)) O ( n k log ( k ) ) 的,但绝对会T。
从最初的式子考虑,我们发现 dis(i,j)k d i s ( i , j ) k 是个幂,于是考虑用第二类stirlng数将其代换:
其中 S(k,p) S ( k , p ) 是第二类stirling数。由于当 p>k p > k 时 S(k,p) S ( k , p ) 值为0,d的上界还可以跟k取个min。 S(k,p) S ( k , p ) 可以用递推式 S(i,j)=S(i−1,j−1)+S(i−1,j)∗j S ( i , j ) = S ( i − 1 , j − 1 ) + S ( i − 1 , j ) ∗ j 求,也可以用容斥+NTT算一行。不过因为k很小,所以直接递推即可。由于k是定值,为了方便直接记 h[p]=S(k,p)∗(p!) h [ p ] = S ( k , p ) ∗ ( p ! ) 。
现在我们主要关注 Cpd C d p 这一项。不妨令 f[node][p] f [ n o d e ] [ p ] 表示 ∑u∈nodeCpdis(node,u) ∑ u ∈ n o d e C d i s ( n o d e , u ) p 。考虑计算node的父亲fa的f值,发现node子树中的所有点距离+1。根据杨辉三角 Cpd+1=Cpd+Cp−1d C d + 1 p = C d p + C d p − 1 ,可以算出 f[node][p−1]+f[node][p] f [ n o d e ] [ p − 1 ] + f [ n o d e ] [ p ] 对 f[fa][p] f [ f a ] [ p ] 有贡献。同样用两次DFS即可求出所有答案。
一开始我想这题的时候忘了杨辉三角的公式,然后发现从 Cpd C d p 转移到 Cpd+1 C d + 1 p 很困难,以为要对不同的d分开处理,然后就走远了。以后要多做些组合数学的题才行QAQ。
CODE:
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=50100;
const int maxk=160;
const int M=10007;
struct edge
{
int obj;
edge *Next;
} e[maxn<<1];
edge *head[maxn];
int cur=-1;
int f[maxn][maxk];
int g[maxn][maxk];
int S[maxk][maxk];
int h[maxk];
int fac[maxk];
int fa[maxn];
int n,k;
void Add(int x,int y)
{
cur++;
e[cur].obj=y;
e[cur].Next=head[x];
head[x]=e+cur;
}
void Dfs1(int node)
{
f[node][0]=1;
for (edge *p=head[node]; p; p=p->Next)
{
int son=p->obj;
if (son==fa[node]) continue;
fa[son]=node;
Dfs1(son);
f[node][0]=(f[node][0]+f[son][0])%M;
for (int i=1; i<=k; i++)
f[node][i]=(f[node][i]+f[son][i]+f[son][i-1])%M;
}
}
void Dfs2(int node)
{
for (edge *p=head[node]; p; p=p->Next)
{
int son=p->obj;
if (son==fa[node]) continue;
g[son][0]=f[node][0]-f[son][0];
for (int i=0; i<=k; i++)
g[son][i]=(f[node][i]-f[son][i]-f[son][i-1]+2*M)%M;
for (int i=0; i<=k; i++) g[son][i]=(g[son][i]+g[node][i])%M;
for (int i=k; i>=1; i--) g[son][i]=(g[son][i]+g[son][i-1])%M;
Dfs2(son);
}
}
int main()
{
freopen("2159.in","r",stdin);
freopen("2159.out","w",stdout);
int L,now,A,B,Q,tmp;
scanf("%d%d%d",&n,&k,&L);
for (int i=1; i<=n; i++) head[i]=NULL;
scanf("%d%d%d%d",&now,&A,&B,&Q);
for (int i=1; i*A+B)%Q;
tmp=((iint x=i-now%tmp,y=i+1;
Add(x,y);
Add(y,x);
}
for (int i=1; i<=k; i++) S[i][1]=1;
for (int i=2; i<=k; i++)
for (int j=2; j<=i; j++)
S[i][j]=(S[i-1][j-1]+S[i-1][j]*j)%M;
fac[0]=1;
for (int i=1; i<=k; i++) fac[i]=fac[i-1]*i%M;
for (int i=1; i<=k; i++) h[i]=S[k][i]*fac[i]%M;
Dfs1(1);
Dfs2(1);
for (int i=1; i<=n; i++)
{
int ans=0;
for (int j=0; j<=k; j++) ans=(ans+ (f[i][j]+g[i][j])*h[j] )%M;
printf("%d\n",ans);
}
return 0;
}