题目大意:
对于一个无向图
G
G
G,假设
G
G
G中有
x
x
x个联通块为树,那么
G
G
G的权值就为
x
k
x^k
xk(
k
k
k给定)
给定
n
,
k
n,k
n,k求
n
n
n个点的所有无向图的权值之和
对
998244353
998244353
998244353取模
n
≤
3
∗
1
0
4
,
k
≤
20
n\le 3*10^4,k\le 20
n≤3∗104,k≤20
s
o
l
u
t
i
o
n
solution
solution:
考虑一个
n
3
n^3
n3暴力,
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示
i
i
i个点,构成
j
j
j棵树的方案数
再统计一下
x
x
x个点没有树联通块的方案树就可以统计答案了
d
p
dp
dp的过程可以
N
T
T
NTT
NTT优化到
n
2
l
o
g
n
n^2logn
n2logn
求 ∑ i i k \sum_i i^k ∑iik可以很容易的想到用斯特林数展开
考虑一个图
G
G
G的贡献,假设他有
x
x
x个联通块为树
x
k
=
∑
j
{
k
j
}
x
j
‾
=
∑
j
{
k
j
}
C
x
j
∗
j
!
x^k=\sum_{j} \left\{ {k\atop j} \right\} x^{\underline j}\\ =\sum_j \left\{ {k\atop j} \right\} C_x^j * j!
xk=j∑{jk}xj=j∑{jk}Cxj∗j!
考虑一下这个式子
C
x
j
C_x^j
Cxj相当于是从这
x
x
x个联通块中挑出
j
j
j个联通块,那就意味着我们可以把
x
x
x的贡献摊到所有大小为
j
≤
k
j\le k
j≤k的联通块上。
这样对于所有的图我们就可以一起算贡献了
考虑复杂度,
f
[
i
]
[
j
]
f[i][j]
f[i][j]第二位只要求到
k
k
k
复杂度
O
(
n
k
l
o
g
n
)
O(nklogn)
O(nklogn)
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
int rd()
{
int num = 0;char c = getchar();bool flag = true;
while(c < '0'||c > '9') {if(c == '-') flag = false;c = getchar();}
while(c >= '0' && c <= '9') num = num*10+c-48,c = getchar();
if(flag) return num;else return -num;
}
const int p = 998244353,g = 3;
int n,k;
int f[30100][25],s[25][25];
int fac[30100],inv[30100],flen,inv_n;
int a[120100],b[120100],r[120100],w[120100];
inline int calc(int a,int b){return (a+=b)>=p?a-=p:a;}
inline int mul(int a,int b){return 1ll*a*b%p;}
inline int del(int a,int b){return (a-=b)<0?a+=p:a;}
inline int ksm(int a,int x){int now = 1;for(;x;x>>=1,a=1ll*a*a%p)if(x&1)now=1ll*now*a%p;return now;}
inline int min(int a,int b){return a<b?a:b;}
inline void swap(int &a,int &b){a^=b;b^=a;a^=b;}
inline int C(int i,int j){
if(j > i) return 0;
return (j==0||j==i)?1:mul(fac[i],mul(inv[j],inv[i-j]));
}
void fft(int *a,int f)
{
w[0] = 1;
rep(i,1,flen-1) if(i < r[i]) swap(a[i],a[r[i]]);
for(int len = 2;len <= flen;len <<= 1)
{
int wn = ksm(g,(p-1)/len);
if(f == 1) wn = ksm(wn,p-2);
rep(i,1,len/2) w[i] = mul(w[i-1],wn);
for(int st = 0;st < flen;st += len)
rep(i,0,len/2-1)
{
int x = a[st+i],y = mul(w[i],a[st+i+len/2]);
a[st+i] = calc(x,y);
a[st+i+len/2] = del(x,y);
}
}
}
void work()
{
rep(i,n,flen-1) a[i] = b[i] = 0;
fft(a,1);fft(b,1);
rep(i,0,flen-1) a[i] = mul(a[i],b[i]);
fft(a,-1);
rep(i,0,flen-1) a[i] = mul(a[i],inv_n);
}
int main()
{
n = rd();k = rd();flen = 1;
while(flen < 2*n-1) flen <<= 1; inv_n = ksm(flen,p-2);
rep(i,0,flen-1) r[i] = (r[i>>1]>>1) | ((i&1)?flen/2:0);
s[0][0] = 1; fac[0] = inv[0] = 1;
rep(i,1,k) rep(j,1,i) s[i][j] = calc(s[i-1][j-1],mul(j,s[i-1][j]));
rep(i,1,n) fac[i] = mul(fac[i-1],i),inv[i] = ksm(fac[i],p-2);
rep(i,1,n) f[i][1] = i<2?1:ksm(i,i-2);
rep(j,2,k)
{
rep(i,0,n-1) a[i] = mul(f[i+1][1],inv[i]);
rep(i,0,n-1) b[i] = mul(f[i+1][j-1],inv[i+1]);
work();
rep(i,j,n) f[i][j] = mul(a[i-2],fac[i-1]);
}
int ans = 0;
rep(i,1,n)
rep(j,1,k)
ans = calc(ans , mul( f[i][j] , mul( ksm(2,C(n-i,2)) , mul( C(n,i) , mul( fac[j] , s[k][j] ) ) ) ) );
printf("%d\n",ans);
return 0;
}