1. 程式人生 > >BZOJ 5093: [Lydsy1711月賽]圖的價值

BZOJ 5093: [Lydsy1711月賽]圖的價值

第二類斯特林數模版題

需要一些組合數的小$ trick$


傳送門:here

題意:求所有$ n$個節點的無重邊自環圖的價值和,定義一張圖的價值為每個點度數的$ k$次方和,點有標號


$ Solution$

顯然每個節點的貢獻是獨立的

列舉每個節點的度數,和這個點不聯通的邊可連可不連

$ ans=n*2^{\frac{(n-1)(n-2)}{2}}\ \ \sum\limits_{i=0}^{n-1}i^kC_{n-1}^i$

我們實際要求解的東西就是$ f(n,m)=\sum\limits_{i=0}^ni^mC_n^i$

把$i^m$用斯特林數展開得
$f(n,m)=\sum\limits_{i=0}^n\sum\limits_{j=0}^mC_i^jS(m,j)j!C_n^i$

把$j$移動到前面得
$f(n,m)=\sum\limits_{j=0}^mS(m,j)j!\sum\limits_{i=0}^nC_i^jC_n^i$
考慮後面這個$\sum\limits_{i=0}^nC_i^jC_n^i$是什麼
本質相當於在$n$個物品中選出集合$A$,再在集合$A$中選取$j$個物品
也就是在$n$個物品中選取$j$個物品,其他$n-j$個物品可在集合$A$中也可不在
因此$\sum\limits_{i=0}^nC_i^jC_n^i=C_n^j2^{n-j}$
$f(n,m)=\sum\limits_{j=0}^mS(m,j)j!C_n^j2^{n-j}$
$NTT$篩出斯特林數直接計算即可
複雜度$O(k \ log \ k)$


 

$my \ code$

#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define p 998244353
#define file(x)freopen(x".in","r",stdin);freopen(x".out","w",stdout)
#define rt register int
#define
ll long long using namespace std; inline ll read(){ ll x = 0; char zf = 1; char ch = getchar(); while (ch != '-' && !isdigit(ch)) ch = getchar(); if (ch == '-') zf = -1, ch = getchar(); while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); return x * zf; } void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);} void writeln(const ll y){write(y);putchar('\n');} int i,j,k,m,n,x,y,z,cnt; int a[1000010],b[1000010],R[1000010],lim; ll ksm(ll x,ll y){ if(!y)return 1;ll ew=1; while(y>1){ if(y&1)y--,ew=x*ew%p; y>>=1,x=x*x%p; }return x*ew%p; } int inv[200010],S[200010]; struct poly{ int n,m,lim; void init(int k){ //a[i]=(-1)^i / i! b[i] = i^k/i! n=k; a[0]=1;b[0]=0; for(rt i=1;i<=k;i++){ a[i]=-1ll*a[i-1]*inv[i]%p; b[i]=ksm(i,k)*a[i]%p; if(i&1)b[i]=-b[i]; } lim=1;while(lim<=n+n)lim<<=1; for(rt i=1;i<lim;i++)R[i]=(R[i>>1]>>1)|(i&1?(lim>>1):0); } void NTT(int *A,int fla){ for(rt i=0;i<lim;i++)if(i<R[i])swap(A[i],A[R[i]]); for(rt i=1;i<lim;i<<=1){ ll w=ksm(3,p/2/i); for(rt j=0;j<lim;j+=i<<1){ ll K=1; for(rt k=0;k<i;k++,K=K*w%p){ ll x=A[j+k],y=K*A[i+j+k]; A[j+k]=(x+y)%p;A[i+j+k]=(x-y)%p; } } } if(fla==-1){ reverse(A+1,A+lim); for(rt i=0;i<=n;i++)S[i]=1ll*A[i]*ksm(lim,p-2)%p; } } void main(int k){ init(k); NTT(a,1);NTT(b,1); for(rt i=0;i<lim;i++)a[i]=1ll*a[i]*b[i]%p; NTT(a,-1); } }NTT; int main(){ n=read()-1;k=read(); inv[0]=inv[1]=1; for(rt i=2;i<=k+1;i++)inv[i]=1ll*inv[p%i]*(p-p/i)%p; NTT.main(k); ll jc=1,C=1,ans=0,sum=ksm(2,n-j); for(rt j=0;j<=k;j++){ (ans+=S[j]*jc%p*C%p*sum)%=p; jc=jc*(j+1)%p;C=C*(n-j)%p*inv[j+1]%p; sum=sum*inv[2]%p; } cout<<(ans*(n+1)%p*ksm(2,(ll)n*(n-1)/2)%p+p)%p; return 0; }