BZOJ 5093: [Lydsy1711月赛]图的价值
第二类斯特林数模版题
需要一些组合数的小$ trick$
upd:这里更新了本题巧妙的$ O(k)$做法,虽然常数很大就是了
传送门: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; }