题意
“简单无向图”是指无重边、无自环的无向图(不一定连通)。
一个带标号的图的价值定义为每个点度数的k次方的和。
给定n和k,请计算所有n个点的带标号的简单无向图的价值之和。
因为答案很大,请对998244353取模输出。
1<=n<=10^9,1<=k<=200000
分析
枚举每个点和每个点连出去的边的数量,总共有n-1个点可以连,然后剩下的边连不连都可以。不难分析出
ans=n∗2(n−1)∗(n−2)2∗∑i=0n−1Cin−1∗ik
现在要求的就是
∑i=0nCin∗ik
有一个结论就是
nk=∑i=0nS(k,i)∗Cin∗i!
其中 S(k,i) 是第二类斯特林数。
那么有
∑i=0nCin∗ik
=∑i=0nCin∗∑j=0iS(k,j)∗Cji∗j!
=∑j=0nS(k,j)∗j!∗∑i=jnCin∗Cji
其中 ∑i=jnCin∗Cji 的组合意义是从n个数里面选i个数,再从这i个数里面选j个数,等价于从n个数里面选j个数然后其他的数选或不选都行,也就是 Cjn∗2n−j
所以接着往下推就是
=∑j=0nS(k,j)∗j!∗Cjn∗2n−j
考虑到用容斥原理得出的第二类斯特林数的卷积形式
S(n,m)=1m!∗∑i=0m(−1)i∗Cim∗(m−i)n=∑i=0m(−1)ii!∗(m−i)n(m−i)!
那么我们就可以用NTT把第二类斯特林数求出来,然后预处理组合数来算贡献即可。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=200005;
const int MOD=998244353;
int n,k,jc[N],ny[N],pow[N],rev[N*4],s[N*4],s1[N*4],L,nyL,lg,jcn[N];
int ksm(int x,int y)
{
int ans=1;
while (y)
{
if (y&1) ans=(LL)ans*x%MOD;
x=(LL)x*x%MOD;y>>=1;
}
return ans;
}
void NTT(int *a,int f)
{
for (int i=0;i<L;i++) if (i<rev[i]) swap(a[i],a[rev[i]]);
for (int i=1;i<L;i<<=1)
{
int wn=ksm(3,f==1?(MOD-1)/i/2:MOD-1-(MOD-1)/i/2);
for (int j=0;j<L;j+=(i<<1))
{
int w=1;
for (int k=0;k<i;k++)
{
int u=a[j+k],v=(LL)a[j+k+i]*w%MOD;
a[j+k]=(u+v)%MOD;a[j+k+i]=(u-v)%MOD;
w=(LL)w*wn%MOD;
}
}
}
if (f==-1) for (int i=0;i<L;i++) a[i]=(LL)a[i]*nyL%MOD;
}
int main()
{
scanf("%d%d",&n,&k);n--;
jc[0]=ny[0]=jc[1]=ny[1]=pow[0]=1;pow[1]=2;
for (int i=2;i<=k;i++) jc[i]=(LL)jc[i-1]*i%MOD,ny[i]=(LL)(MOD-MOD/i)*ny[MOD%i]%MOD,pow[i]=pow[i-1]*2%MOD;
for (int i=2;i<=k;i++) ny[i]=(LL)ny[i]*ny[i-1]%MOD;
for (int i=0;i<=k;i++) s[i]=((i&1)?-1:1)*ny[i],s1[i]=(LL)ksm(i,k)*ny[i]%MOD;
jcn[0]=1;
for (int i=1;i<=k;i++) jcn[i]=(LL)jcn[i-1]*(n-i+1)%MOD;
for (L=1;L<=k*2;L<<=1,lg++);nyL=ksm(L,MOD-2);
for (int i=0;i<L;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1));
NTT(s,1);NTT(s1,1);
for (int i=0;i<L;i++) s[i]=(LL)s[i]*s1[i]%MOD;
NTT(s,-1);
int ans=0;
for (int i=0;i<=min(n,k);i++) (ans+=(LL)s[i]*jc[i]%MOD*jcn[i]%MOD*ny[i]%MOD*ksm(2,n-i)%MOD)%=MOD;
ans=(LL)ans*(n+1)%MOD*ksm(2,(LL)n*(n-1)/2%(MOD-1))%MOD;
ans+=ans<0?MOD:0;
printf("%d",ans);
return 0;
}