简要题意:here
题解:
设 c ( G ) c(G) c(G) 表示图 G G G 的联通块数量,首先利用第二类斯特林数转成下降幂:
n m = ∑ k = 0 m S m , k n k ‾ n^m=\sum_{k=0}^mS_{m,k}n^{\underline k} nm=k=0∑mSm,knk
考虑 c ( G ) k ‾ c(G)^{\underline k} c(G)k 的意义,就是有序选择 k k k 个连通块的方案数,这部分有点像 小C的岛屿 的处理方式。
设 f i , n f_{i,n} fi,n 表示所有 n n n 个点的图有序选择 i i i 个连通块的方案数之和。
设 g i g_i gi 表示 i i i 个点的连通图个数,这个多项式求逆算一下就行了。
f f f 的转移也很明显 f i , n = ∑ k = 1 n g k ( n k ) f i − 1. n − k f_{i,n}=\sum_{k=1}^ng_k{n\choose k}f_{i-1.n-k} fi,n=k=1∑ngk(kn)fi−1.n−k
由于 m m m 很小,对于所有要用的 f f f 暴力处理即可。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using std::cerr;
using std::cout;
cs int mod=998244353;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b){return a-b<0?a-b+mod:a-b;}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int po(int a,int b){int r=1;for(;b;b>>=1,Mul(a,a))if(b&1)Mul(r,a);return r;}
inline void ex_gcd(int a,int b,int &x,int &y){
if(!b){x=1,y=0;return;}ex_gcd(b,a%b,y,x);y-=a/b*x;
}inline int Inv(int a){static int x,y;ex_gcd(mod,a,y,x);return x+(x>>31&mod);}
cs int bit=17,SIZE=1<<bit|7;
int r[SIZE],*w[bit+1];
void init_omega(){
for(int re i=1;i<=bit;++i)
w[i]=new int[1<<(i-1)];
w[bit][0]=1;int wn=po(3,(mod-1)>>bit);
for(int re i=1;i<(1<<(bit-1));++i)
w[bit][i]=mul(w[bit][i-1],wn);
for(int re j=bit-1;j;--j)
for(int re i=0;i<(1<<(j-1));++i)
w[j][i]=w[j+1][i<<1];
}
int fac[SIZE],ifc[SIZE],inv[SIZE];
void init_fac(){
fac[0]=fac[1]=1;
ifc[0]=ifc[1]=1;
inv[0]=inv[1]=1;
for(int re i=2;i<SIZE;++i){
fac[i]=mul(fac[i-1],i);
inv[i]=mul(inv[mod%i],mod-mod/i);
ifc[i]=mul(ifc[i-1],inv[i]);
}
}
int len,inv_len;
void init_len(int l){
len=l;inv_len=inv[l];
for(int re i=1;i<l;++i)
r[i]=r[i>>1]>>1|((i&1)?l>>1:0);
}
void DFT(int *A){
for(int re i=1;i<len;++i)
if(i<r[i])std::swap(A[i],A[r[i]]);
for(int re i=1,d=1;i<len;i<<=1,++d)
for(int re j=0;j<len;j+=i<<1)
if(i<8){
for(int re k=0;k<i;++k){
int &t1=A[j+k],&t2=A[i+j+k];
int t=mul(t2,w[d][k]);
t2=dec(t1,t);Inc(t1,t);
}
}else {
#define work(p) \
{ \
int &t1=A[j+k+p],&t2=A[i+j+k+p]; \
int t=mul(t2,w[d][k+p]); \
t2=dec(t1,t);Inc(t1,t); \
}
for(int re k=0;k<i;k+=8){
work(0);work(1);work(2);work(3);
work(4);work(5);work(6);work(7);
}
}
}void IDFT(int *A){
DFT(A);std::reverse(A+1,A+len);
for(int re i=0;i<len;++i)Mul(A[i],inv_len);
}
typedef std::vector<int> Poly;
inline void DFT(Poly &A){DFT(&A[0]);}
inline void IDFT(Poly &A){IDFT(&A[0]);}
void Inv(int *a,int n,int *b){
static int c[SIZE];b[0]=Inv(a[0]);
for(int re l=4;(l>>2)<n;l<<=1){
memcpy(c,a,sizeof(int)*(l>>1));
memset(c+(l>>1),0,sizeof(int)*(l>>1));
memset(b+(l>>2),0,sizeof(int)*(l-(l>>2)));
init_len(l);DFT(b),DFT(c);
for(int re i=0;i<l;++i)
Mul(b[i],dec(2,mul(b[i],c[i])));
IDFT(b);
}
}
cs int M=20;
int S[M][M];
int f[M][SIZE];
int G[SIZE];
int A[SIZE],B[SIZE],C[SIZE];
void Main(){
init_omega();init_fac();
S[0][0]=1;
for(int re i=1;i<M;++i)
for(int re j=1;j<M;++j)
S[i][j]=add(S[i-1][j-1],mul(S[i-1][j],j));
int n=1<<15;init_len(n+n);
for(int re i=1;i<n;++i){
int pw=po(2,(i-1ll)*i/2%(mod-1));
A[i]=mul(pw,ifc[i-1]);
B[i]=mul(pw,ifc[i]);
}B[0]=1;Inv(B,n,C);
memset(C+n,0,sizeof(int)*n);
DFT(A),DFT(C);
for(int re i=0;i<len;++i)
G[i]=mul(A[i],C[i]);
IDFT(G);
memset(G+n,0,sizeof(int)*n);
for(int re i=1;i<n;++i)
Mul(G[i],inv[i]);
DFT(G);
memcpy(f[0],B,sizeof(int)*n);
for(int re i=1;i<=15;++i){
memcpy(A,f[i-1],sizeof(int)*len);
DFT(A);for(int re j=0;j<len;++j)
f[i][j]=mul(A[j],G[j]);
IDFT(f[i]);memset(f[i]+n,0,sizeof(int)*n);
}
int T;scanf("%d",&T);
while(T--){
int n,m,ans=0;
scanf("%d%d",&n,&m);
for(int re i=0;i<=m;++i)
Inc(ans,mul(S[m][i],mul(f[i][n],fac[n])));
cout<<ans<<"\n";
}
}
inline void file(){
#ifdef zxyoi
freopen("dark.in","r",stdin);
#else
freopen("dark.in","r",stdin);
freopen("dark.out","w",stdout);
#endif
}signed main(){file();Main();return 0;}