版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/86358630
Description
“简单无向图”是指无重边、无自环的无向图(不一定连通)。
一个带标号的图的价值定义为每个点度数的k次方的和。
给定n和k,请计算所有n个点的带标号的简单无向图的价值之和。
因为答案很大,请对
取模输出。
第一行包含两个正整数
Solution
注意到每个点的贡献都是一样的,我们只需要枚举每个点的度数单独考虑就行了
然后就是非常套路的
带进去就是
交换枚举顺序
然后有等柿
为什么呢?两个组合数相乘的意义等价于从 个中直接取出 个,剩余 个随便选。或者直接化也可以
于是我们的答案可以这么算
注意到 的时候斯特林数为 ,因此只需要算到 即可
斯特林数用容斥柿子NTT算,预处理阶乘和逆元就可以惹
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
typedef long long LL;
const int MOD=998244353;
const int ny2=499122177;
const int N=1048580;
LL fac[N],rev[N],s[N],ny[N];
LL ksm(LL x,LL dep) {
LL res=1;
for (;dep;dep>>=1) {
(dep&1)?(res=res*x%MOD):0;
x=x*x%MOD;
}
return res;
}
LL mod(LL x) {
(x>=MOD)?(x-=MOD):0;
(x<0)?(x+=MOD):0;
return x;
}
void NTT(LL *a,int n,int f) {
for (int i=0;i<n;++i) if (i<rev[i]) std:: swap(a[i],a[rev[i]]);
for (int i=1;i<n;i<<=1) {
LL wn=0;
if (f==1) wn=ksm(3,(MOD-1)/i/2);
else wn=ksm(3,(MOD-1)-(MOD-1)/i/2);
for (int j=0;j<n;j+=(i<<1)) {
LL w=1;
for (int k=0;k<i;++k) {
LL u=a[j+k],v=a[j+k+i]*w%MOD;
a[j+k]=mod(u+v); a[j+k+i]=mod(u-v);
w=w*wn%MOD;
}
}
}
if (f==-1) {
LL ny=ksm(n,MOD-2);
for (int i=0;i<n;++i) a[i]=ny*a[i]%MOD;
}
}
int n,m;
void pre() {
scanf("%d%d",&n,&m);
fac[0]=ny[0]=1; for(int i=1;i<N;++i) {
fac[i]=fac[i-1]*i%MOD;
}
ny[N-1]=ksm(fac[N-1],MOD-2);
for (int i=N-2;i>=0;--i) {
ny[i]=ny[i+1]*(i+1)%MOD;
}
static LL b[N];
int len=1,lg=0; for (;len<=m*2;len<<=1,++lg);
for (int i=0;i<len;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1));
for (int i=0;i<=m;++i) {
s[i]=ny[i];
if (i&1) s[i]=MOD-s[i];
b[i]=ksm(i,m)*ny[i]%MOD;
}
NTT(s,len,1); NTT(b,len,1);
for (int i=0;i<len;++i) s[i]=s[i]*b[i]%MOD;
NTT(s,len,-1);
}
int main(void) {
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
pre();
LL ans=0,lxf=1;
for (int i=0,lim=std:: min(n-1,m);i<=lim;++i) {
LL tmp=ksm(2,n-i-1)*s[i]%MOD*lxf%MOD*ny[i]%MOD*fac[i]%MOD;
ans=mod(ans+tmp);
lxf=lxf*(n-i-1)%MOD;
}
ans=n*ksm(2,1LL*(n-1)*(n-2)/2)%MOD*ans%MOD;
printf("%lld\n", ans);
return 0;
}