题目描述
n个点的无向图,每条边都可能存在,一个图的权值是连通块个数的m次方,求所有可能的图的权值和,答案对998244353取模。
数据范围
T ≤ 1000 , n ≤ 30000 , m ≤ 15 T \le 1000,n \le 30000,m \le 15 T≤1000,n≤30000,m≤15
题解
设
h
n
,
i
h_{n,i}
hn,i 表示
n
n
n 个点的图有
i
i
i 个连通块的方案数,答案可以写成
∑
k
=
1
n
h
n
,
k
k
m
\sum_{k=1}^nh_{n,k}k^m
k=1∑nhn,kkm
化式子,得
∑
k
=
1
n
h
n
,
k
∑
i
=
1
m
{
i
m
}
(
i
k
)
i
!
\sum_{k=1}^nh_{n,k}\sum_{i=1}^m\{_i^m\}(_i^k)i!
k=1∑nhn,ki=1∑m{im}(ik)i!
其中
{
i
m
}
\{_i^m\}
{im} 代表第二类斯特林数。将
i
i
i 提前,得
∑
i
=
1
m
{
i
m
}
i
!
∑
k
=
1
n
h
n
,
k
(
i
k
)
\sum_{i=1}^m\{_i^m\}i!\sum_{k=1}^nh_{n,k}(_i^k)
i=1∑m{im}i!k=1∑nhn,k(ik)
设
f
n
,
i
=
∑
k
=
1
n
h
n
,
k
(
i
k
)
f_{n,i}=\sum_{k=1}^nh_{n,k}(_i^k)
fn,i=∑k=1nhn,k(ik) , 则上述式子为
∑
i
=
1
m
{
i
m
}
i
!
f
n
,
i
\sum_{i=1}^m\{_i^m\}i!f_{n,i}
i=1∑m{im}i!fn,i
接着我们化简
f
n
,
i
f_{n,i}
fn,i , 可以枚举编号为1的点所在的连通块大小,我们预处理
g
i
g_i
gi 表示i个点的图是连通的的方案数,这个就是城市规划那题要求的,我们可以得到
f
n
,
i
=
∑
k
=
1
n
(
i
k
)
∑
j
=
1
n
−
k
+
1
(
j
−
1
n
−
1
)
g
j
h
n
−
j
,
k
−
1
f_{n,i}=\sum_{k=1}^n(_i^k)\sum_{j=1}^{n-k+1}(_{j-1}^{n-1})g_jh_{n-j,k-1}
fn,i=k=1∑n(ik)j=1∑n−k+1(j−1n−1)gjhn−j,k−1
由组合数的递推式得
f
n
,
i
=
∑
j
=
1
n
(
j
−
1
n
−
1
)
g
j
∑
k
=
1
n
−
j
+
1
(
(
i
−
1
k
−
1
)
+
(
i
k
−
1
)
)
h
n
−
j
,
k
−
1
f_{n,i}=\sum_{j=1}^n(_{j-1}^{n-1})g_j\sum_{k=1}^{n-j+1}((_{i-1}^{k-1})+(_i^{k-1}))h_{n-j,k-1}
fn,i=j=1∑n(j−1n−1)gjk=1∑n−j+1((i−1k−1)+(ik−1))hn−j,k−1
用
k
k
k 取代
k
−
1
k-1
k−1 ,得
f
n
,
i
=
∑
j
=
1
n
(
j
−
1
n
−
1
)
g
j
(
f
n
−
j
,
i
−
1
+
f
n
−
j
,
i
)
f_{n,i}=\sum_{j=1}^n(_{j-1}^{n-1})g_j(f_{n-j,i-1}+f_{n-j,i})
fn,i=j=1∑n(j−1n−1)gj(fn−j,i−1+fn−j,i)
于是我们可以得到
f
i
,
n
=
(
n
−
1
)
!
∑
j
=
1
n
g
j
(
j
−
1
)
!
f
i
−
1
,
n
−
j
(
n
−
j
)
!
+
g
j
(
j
−
1
)
!
f
i
,
n
−
j
(
n
−
j
)
!
f_{i,n}=(n-1)!\sum_{j=1}^n\frac{g_j}{(j-1)!}\frac{f_{i-1,n-j}}{(n-j)!}+\frac{g_j}{(j-1)!}\frac{f_{i,n-j}}{(n-j)!}
fi,n=(n−1)!j=1∑n(j−1)!gj(n−j)!fi−1,n−j+(j−1)!gj(n−j)!fi,n−j
于是我们就可以分治
N
t
t
Ntt
Ntt 求出
f
i
(
x
)
f_i(x)
fi(x) 效率:
O
(
n
l
o
g
2
n
)
O(nlog^2n)
O(nlog2n)
代码
#include <bits/stdc++.h>
using namespace std;
const int M=16,P=998244353,N=30001,Z=N<<2;
int ans,T,n,m,s[M][M],jc[N],ny[N],g[Z],b[Z],c[Z],d[Z],A[Z],B[Z],f[M][N],t,p,G[2]={3,(P+1)/3},r[Z];
int X(int x){if (x>=P) x-=P;return x;}
int K(int x,int y){
int A=1;
for (;y;y>>=1,x=1ll*x*x%P)
if (y&1) A=1ll*A*x%P;
return A;
}
void Ntt(int *g,bool o){
for (int i=0;i<t;i++)
if (i<r[i]) swap(g[i],g[r[i]]);
for (int wn,i=1;i<t;i<<=1){
wn=K(G[o],(P-1)/(i<<1));
for (int x,y,j=0;j<t;j+=(i<<1))
for (int w=1,k=0;k<i;k++,w=1ll*w*wn%P)
x=g[j+k],y=1ll*w*g[i+j+k]%P,
g[j+k]=X(x+y),g[i+j+k]=X(x-y+P);
}
if (o)
for (int i=0,v=K(t,P-2);i<t;i++)
g[i]=1ll*v*g[i]%P;
}
void pre(int l){
for (t=1,p=0;t<l;t<<=1,p++);
for (int i=0;i<t;i++)
r[i]=(r[i>>1]>>1)|((i&1)<<(p-1));
}
void getinv(int *a,int *b,int l){
if (l==1){
b[0]=K(a[0],P-2);return;
}
getinv(a,b,(l+1)>>1);
for (int i=0;i<l;i++)
A[i]=a[i],B[i]=b[i];
pre(l+l);Ntt(A,0);Ntt(B,0);
for (int i=0;i<t;i++)
A[i]=1ll*A[i]*B[i]%P*B[i]%P;
Ntt(A,1);for (int i=0;i<l;i++)
b[i]=X(X(b[i]+b[i])-A[i]+P);
for (int i=0;i<t;i++) A[i]=B[i]=0;
}
void solve(int *a,int l,int r){
if (l==r){
a[l]=X(a[l]+d[l]);
if (l) a[l]=1ll*a[l]*jc[l-1]%P;
return;
}
int mid=(l+r)>>1;solve(a,l,mid);
for (int i=0;i<=mid-l;i++) b[i]=1ll*a[l+i]*ny[l+i]%P;
for (int i=0;i<r-l;i++) c[i]=1ll*g[i+1]*ny[i]%P;
pre(mid-l+1+r-l);Ntt(b,0);Ntt(c,0);
for (int i=0;i<t;i++) b[i]=1ll*b[i]*c[i]%P;
Ntt(b,1);for (int i=mid+1;i<=r;i++) a[i]=X(a[i]+b[i-l-1]);
for (int i=0;i<t;i++) b[i]=c[i]=0;
solve(a,mid+1,r);
}
int main(){
s[0][0]=1;
for (int i=1;i<M;i++)
for (int j=1;j<=i;j++)
s[i][j]=(s[i-1][j-1]+1ll*s[i-1][j]*j%P)%P;
jc[0]=1;
for (int i=1;i<N;i++) jc[i]=1ll*i*jc[i-1]%P;
ny[N-1]=K(jc[N-1],P-2);
for (int i=N-1;i;i--) ny[i-1]=1ll*i*ny[i]%P;
for (int i=0;i<N;i++)
g[i]=1ll*K(2,(1ll*i*(i-1)/2)%(P-1))*ny[i]%P;
getinv(g,b,N);
for (int i=0;i<N;i++)
g[i]=1ll*K(2,(1ll*i*(i-1)/2)%(P-1))*ny[i-1]%P;
pre(N+N);Ntt(g,0);Ntt(b,0);
for (int i=0;i<t;i++) g[i]=1ll*g[i]*b[i]%P,b[i]=0;
Ntt(g,1);for (int i=1;i<N;i++) g[i]=1ll*g[i]*jc[i-1]%P;
for (int i=0;i<M;i++){
if (!i){d[0]=g[0]=1;goto out;}
for (int j=1;j<N;j++)
b[j]=1ll*g[j]*ny[j-1]%P,
c[N-j-1]=1ll*f[i-1][N-j-1]*ny[N-j-1]%P;
pre(N+N);Ntt(b,0),Ntt(c,0);
for (int j=0;j<t;j++)
d[j]=1ll*b[j]*c[j]%P,b[j]=c[j]=0;
Ntt(d,1);out:;solve(f[i],0,N-1);
}
for (scanf("%d",&T);T--;){
scanf("%d%d",&n,&m);ans=0;
for (int i=1;i<=m;i++)
ans=X(ans+1ll*s[m][i]*f[i][n]%P*jc[i]%P);
printf("%d\n",ans);
}
return 0;
}