luogu P4827 [国家集训队] Crash 的文明世界
题面传送门
发现自己不会斯特林反演于是去学习了一下。
大概就是\(m^n=\sum\limits_{i=0}^{m}{C^{m}_{i} \{^n_{i}\}i!}\)
感性理解一下就是\(m^n\)是把\(n\)个球放到\(m\)个不同的盒子里。所以枚举非空的盒子然后斯特林数最后因为斯特林数无序所以乘以\(j!\)即可。
然后这道题式子就变成了\(\sum\limits_{i=1}^{n}{\sum\limits_{j=0}^{k}{C^{dist(x,i)}_{j}j!\{^k_j\}}}\)
换个顺序变成\(\sum\limits_{j=0}^{k}{j!\{^k_j\}\sum\limits_{i=1}^{n}{C^{dist(x,i)}_{j}}}\)
组合恒等式就有\(\sum\limits_{j=0}^{k}{j!\{^k_j\}\sum\limits_{i=1}^{n}{C^{dist(x,i)-1}_{j-1}+C^{dist(x,i)-1}_{j}}}\)
然后换根dp就好了。时间复杂度\(O(nk)\)
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 50000
#define K 150
#define mod 10007
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
using namespace std;
int n,m,k,S[K+5][N+5],dp[N+5][K+5],F[N+5][K+5],x,y,frc[N+5],Ans;
struct yyy{int to,z;};
struct ljb{int head,h[N+5];yyy f[N+5<<1];I void add(int x,int y){f[++head]=(yyy){y,h[x]};h[x]=head;}}s;
I void calc(int *A,int *B,int x){re int i;for(A[0]=(A[0]+B[0]*x+mod)%mod,i=1;i<=k;i++) A[i]=(A[i]+(B[i]+B[i-1])*x+2*mod)%mod;}
I void dfs1(int x,int last){
int i;dp[x][0]=1;yyy tmp;for(i=s.h[x];i;i=tmp.z)tmp=s.f[i],tmp.to^last&&(dfs1(tmp.to,x),calc(dp[x],dp[tmp.to],1),0);memcpy(F[x],dp[x],sizeof(F[x]));
}
I void dfs2(int x,int last){
int i,j;yyy tmp;for(i=s.h[x];i;i=tmp.z)tmp=s.f[i],tmp.to^last&&(calc(F[x],dp[tmp.to],-1),calc(F[tmp.to],F[x],1),calc(F[x],dp[tmp.to],1),dfs2(tmp.to,x),0);
}
int main(){
freopen("1.in","r",stdin);
re int i,j;scanf("%d%d",&n,&k);for(i=1;i<n;i++) scanf("%d%d",&x,&y),s.add(x,y),s.add(y,x);S[0][0]=1;for(i=1;i<=k;i++) for(j=1;j<=k;j++) S[i][j]=(S[i-1][j-1]+S[i-1][j]*j)%mod;
dfs1(1,0);dfs2(1,0); for(frc[0]=i=1;i<=k;i++) frc[i]=frc[i-1]*i%mod;for(i=1;i<=n;i++){for(Ans=j=0;j<=k;j++) Ans=(Ans+S[k][j]*frc[j]%mod*F[i][j])%mod;printf("%d\n",Ans);}
}