题目大意:
对所
n
n
n个点的连通图
G
\mathrm{G}
G求边数的
k
k
k次方和。
n
≤
5
×
1
0
4
,
k
≤
15
n\le5\times10^4,k\le15
n≤5×104,k≤15
题解:
显然考虑斯特林数:
m
k
=
∑
i
=
0
k
S
(
k
,
i
)
i
!
(
m
i
)
m^k=\sum_{i=0}^kS(k,i)i!\binom mi
mk=∑i=0kS(k,i)i!(im),因此统计
n
n
n个点的图并选定其中恰好
i
i
i条不同的边的方案数。
那么设
f
m
,
n
f_{m,n}
fm,n表示连通图的情况,
g
m
,
n
g_{m,n}
gm,n表示所有图的情况,那么显然
g
m
,
n
=
(
(
n
2
)
m
)
2
(
n
2
)
−
m
g_{m,n}=\binom{\binom n2}{m}2^{\binom n2-m}
gm,n=(m(2n))2(2n)−m,然后枚举1所在连通块大小:
∑
j
=
0
m
∑
i
=
1
n
(
n
−
1
i
−
1
)
f
j
,
i
g
m
−
j
,
n
−
i
=
g
m
,
n
\sum_{j=0}^m\sum_{i=1}^n\binom{n-1}{i-1}f_{j,i}g_{m-j,n-i}=g_{m,n}
j=0∑mi=1∑n(i−1n−1)fj,igm−j,n−i=gm,n
那么令
[
x
n
]
F
m
(
x
)
=
f
m
,
n
(
n
−
1
)
!
[
x
n
]
G
m
(
x
)
=
g
m
,
n
n
!
[
x
n
]
H
m
(
x
)
=
g
m
,
n
(
n
−
1
)
!
[x^n]F_m(x)=\frac{f_{m,n}}{(n-1)!}\\ [x^n]G_m(x)=\frac{g_{m,n}}{n!}\\ [x^n]H_m(x)=\frac{g_{m,n}}{(n-1)!}
[xn]Fm(x)=(n−1)!fm,n[xn]Gm(x)=n!gm,n[xn]Hm(x)=(n−1)!gm,n
则:
∑
j
=
0
m
F
j
(
x
)
G
m
−
j
(
x
)
=
H
m
(
x
)
\sum_{j=0}^mF_j(x)G_{m-j}(x)=H_m(x)
j=0∑mFj(x)Gm−j(x)=Hm(x)
因此:
F
m
(
x
)
=
H
m
(
x
)
−
∑
j
=
0
m
−
1
F
j
(
x
)
G
m
−
j
(
x
)
G
0
(
x
)
F_m(x)=\frac{H_m(x)-\sum_{j=0}^{m-1}F_j(x)G_{m-j}(x)}{G_0(x)}
Fm(x)=G0(x)Hm(x)−∑j=0m−1Fj(x)Gm−j(x)
时间复杂度
O
(
n
k
2
+
n
k
lg
n
)
O(nk^2+nk\lg n)
O(nk2+nklgn)
顺便重新屯了一波板子(求逆指对)。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define p 998244353
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
inline int fast_pow(int x,int k,int ans=1) { for(k<0?k+=p-1:0;k;k>>=1,x=(lint)x*x%p) (k&1)?ans=(lint)ans*x%p:0;return ans; }
namespace POLY_space{
const int N=200000;
int A[N],B[N],C[N],r[N];
inline void clr(int *a,int n) { memset(a,0,sizeof(int)*n); }
inline void cpy(int *a,int *b,int n) { memcpy(a,b,sizeof(int)*n); }
inline int NTT(int *a,int n,int s)
{
rep(i,1,n-1) if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=2;i<=n;i<<=1)
{
int wn=fast_pow(3,(s>0)?(p-1)/i:p-1-(p-1)/i);
for(int j=0,t=i>>1,x,y;j<n;j+=i)
for(int k=0,w=1;k<t;k++,w=(lint)w*wn%p)
x=a[j+k],y=(lint)w*a[j+k+t]%p,
a[j+k]=x+y,(a[j+k]>=p?a[j+k]-=p:0),
a[j+k+t]=x-y,(a[j+k+t]<0?a[j+k+t]+=p:0);
}
if(s<0) for(int i=0,ninv=fast_pow(n,p-2);i<n;i++) a[i]=(lint)a[i]*ninv%p;
return 0;
}
inline int tms(int *a,int m1,int *b,int m2,int *c)//a[m1]=b[m2]=0
{
int n=1,L=0;while(n<m1+m2-1) n<<=1,L++;
rep(i,1,n-1) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
clr(A,n),cpy(A,a,m1),NTT(A,n,1);
clr(B,n),cpy(B,b,m2),NTT(B,n,1);
rep(i,0,n-1) A[i]=(lint)A[i]*B[i]%p;
return NTT(A,n,-1),cpy(c,A,m1+m2-1),0;
}
inline int tms(int *a,int m1,int *b,int m2,int *c,int n) { return tms(a,m1,b,m2,C),cpy(c,C,n),0; }
namespace POLYINV_space{
int b[N],h[N];
inline int polyinv(int *a,int m,int *res)//a[m]=0
{
int n=1;while(n<m) n<<=1;
clr(b,n),b[0]=fast_pow(a[0],p-2);
for(int i=2;i<=n;i<<=1)
{
cpy(h,b,i);
rep(j,0,(i>>1)-1) h[j]+=h[j],(h[j]>=p?h[j]-=p:0);
tms(b,i>>1,b,i>>1,b),tms(b,i,a,i,b,i);
rep(j,0,i-1) b[j]=h[j]-b[j],(b[j]<0?b[j]+=p:0);
}
return cpy(res,b,m),0;
}
}using POLYINV_space::polyinv;
inline int polydif(int *a,int n,int *b)
{
rep(i,1,n-1) b[i-1]=(lint)i*a[i]%p;return b[n-1]=0;
}
inline int polyint(int *a,int n,int *b)
{
rep(i,0,n-2) b[i+1]=(lint)a[i]*fast_pow(i+1,p-2)%p;return b[0]=0;
}
namespace POLYLN_space{
int b[N],c[N];
inline int polyln(int *a,int n,int *res) { return polyinv(a,n,b),polydif(a,n,c),tms(b,n,c,n,b),polyint(b,n,c),cpy(res,c,n),0; }
}using POLYLN_space::polyln;
namespace POLYEXP_space{
int b[N],c[N],d[N];
inline int polyexp(int *a,int m,int *res)
{
int n=1;while(n<(m<<1)) n<<=1;b[0]=1;
clr(d,n),cpy(d,a,m);
for(int i=2;i<=n;i<<=1)
{
polyln(b,i>>1,c);
rep(j,0,(i>>1)-1) c[j]=d[j]-c[j],(c[j]<0?c[j]+=p:0);
c[0]++,(c[0]>=p?c[0]-=p:0),tms(b,i>>1,c,i>>1,b);
}
return cpy(res,b,m),0;
}
}using POLYEXP_space::polyexp;
}using POLY_space::NTT;using POLY_space::polyinv;
using POLY_space::r;using POLY_space::clr;using POLY_space::cpy;
const int N=200000,MXK=17;
int fac[N],facinv[N],s[MXK][MXK];
int F[MXK][N],G[MXK][N],H[MXK][N],G0inv[N];
inline int getstl(int k)
{
s[0][0]=1;
rep(i,1,k) rep(j,1,i) s[i][j]=(s[i-1][j-1]+(lint)j*s[i-1][j])%p;
return 0;
}
inline int C(int n,int m)
{
if(n<0||m<0||n<m) return 0;int ans=1;
rep(i,n-m+1,n) ans=(lint)ans*i%p;
return (lint)ans*facinv[m]%p;
}
inline int prelude(int n)
{
rep(i,fac[0]=1,n) fac[i]=(lint)i*fac[i-1]%p;
facinv[n]=fast_pow(fac[n],p-2);
for(int i=n-1;i>=0;i--) facinv[i]=(i+1ll)*facinv[i+1]%p;
return 0;
}
int main()
{
int n=inn(),k=inn(),g,ans=0;
prelude(max(n,k)),getstl(k);
rep(i,0,k) rep(j,0,n)
g=(lint)C(C(j,2),i)*fast_pow(2,(j*(j-1ll)/2)%(p-1)-i)%p,
G[i][j]=(lint)g*facinv[j]%p,(j?H[i][j]=(lint)g*facinv[j-1]%p:0);
polyinv(G[0],n+1,G0inv);
int z=1,L=0;while(z<=n*2) z<<=1,L++;
rep(i,1,z-1) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
rep(i,0,k) NTT(H[i],z,1),NTT(G[i],z,1);NTT(G0inv,z,1);
rep(i,0,k)
{
cpy(F[i],H[i],z);
rep(j,0,i-1) rep(t,0,z-1) F[i][t]=(F[i][t]-(lint)F[j][t]*G[i-j][t])%p,(F[i][t]<0?F[i][t]+=p:0);
NTT(F[i],z,-1);
rep(j,n+1,z-1) F[i][j]=0;
NTT(F[i],z,1);
rep(j,0,z-1) F[i][j]=(lint)F[i][j]*G0inv[j]%p;
NTT(F[i],z,-1);
rep(j,n+1,z-1) F[i][j]=0;
ans=(ans+(lint)F[i][n]*fac[n-1]%p*fac[i]%p*s[k][i])%p;
NTT(F[i],z,1);
}
return !printf("%d\n",ans);
}