【BZOJ】2159: Crash 的文明世界-第二类斯特林数

传送门:bzoj2159


题解

对于点 x x x答案为 ∑ i = 1 n d i s ( x , i ) k \sum\limits_{i=1}^ndis(x,i)^k i=1ndis(x,i)k

相较二项式展开,第二类斯特林数展开 d i s ( x , i ) k dis(x,i)^k dis(x,i)k是齐次的,得到:
∑ j = 0 k { k j } j ! ∑ i = 1 n ( d i s ( i , x ) j ) \sum\limits_{j=0}^k\left\{\begin{matrix}k\\j\end{matrix}\right\}j!\sum\limits_{i=1}^n\dbinom{dis(i,x)}{j} j=0k{kj}j!i=1n(jdis(i,x))

f x , j = ∑ i = 1 n ( d i s ( i , x ) j ) f_{x,j}=\sum\limits_{i=1}^n\dbinom{dis(i,x)}{j} fx,j=i=1n(jdis(i,x)),可以 O ( k ) O(k) O(k)维护:

f x , j = ∑ f a [ k ] = i f k , j + f k , j − 1 f_{x,j}=\sum\limits_{fa[k]=i}f_{k,j}+f_{k,j-1} fx,j=fa[k]=ifk,j+fk,j1

两遍 d f s dfs dfs即可。


代码

#include
using namespace std;
const int N=5e4+10,M=155,mod=10007;

int n,K,ans,frc[M],s[M][M],f[N][M],rs[M];
int head[N],to[N<<1],nxt[N<<1],tot;

inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}

inline int ad(int x,int y){x+=y;return x>=mod?x-mod:x;}
inline int dc(int x,int y){x-=y;return x<0?x+mod:x;}

void dfs(int x,int fr)
{
	int i,j,k;f[x][0]=1;
	for(i=head[x];i;i=nxt[i]){
		j=to[i];if(j==fr) continue;
		dfs(j,x);f[x][0]=ad(f[x][0],f[j][0]);
		for(k=1;k<=K;++k)
         f[x][k]=ad(f[x][k],ad(f[j][k],f[j][k-1]));
	}
}

void dfss(int x,int fr)
{
	int i,j,k;
	for(i=head[x];i;i=nxt[i]){
		j=to[i];if(j==fr) continue;
		rs[0]=dc(f[x][0],f[j][0]);
		for(k=1;k<=K;++k)
		 rs[k]=dc(f[x][k],ad(f[j][k],f[j][k-1]));
		f[j][0]=ad(f[j][0],rs[0]);
		for(k=1;k<=K;++k)
		 f[j][k]=ad(f[j][k],ad(rs[k],rs[k-1]));
		dfss(j,x);
	}
}

 void Uncompress(FILE *infile, FILE *outfile) { 
    int N, k, L, i, now, A, B, Q, tmp; 
	fscanf(infile, "%d%d%d", &N, &k, &L); 
	fscanf(infile, "%d%d%d%d", &now, &A, &B, &Q); 
	fprintf(outfile, "%d %d\n", N, k); 
	for (i = 1; i < N; i ++) { 
	  now = (now * A + B) % Q; 
	  tmp = (i < L) ? i : L; 
	  fprintf(outfile, "%d %d\n", i - now % tmp, i + 1); 
	} 
} 

int main(){
	
	int i,j,x,y,L,now,A,B,Q,tmp;
	scanf("%d%d%d%d%d%d%d",&n,&K,&L,&now,&A,&B,&Q);
    for (int i=1;i<n;i++){
        now=(now*A+B)%Q;tmp=i<L?i:L;x=i-now%tmp,y=i+1;
        lk(x,y);lk(y,x);
    }
	s[0][0]=1;frc[0]=1;
	for(i=1;i<=K;++i){
		s[i][1]=s[i][i]=1;frc[i]=frc[i-1]*i%mod;
		for(j=2;j<i;++j)
		  s[i][j]=ad(s[i-1][j-1],j*s[i-1][j]%mod);
	}for(i=0;i<=K;++i) frc[i]=frc[i]*s[K][i]%mod;
	dfs(1,0);dfss(1,0);
	for(i=1;i<=n;++i){
		for(ans=j=0;j<=K;++j) ans=ad(ans,frc[j]*f[i][j]%mod);
		printf("%d\n",ans);
	}
	return 0;
}

你可能感兴趣的:(---组合数学---)