首先可以求出
H
(
x
)
H(x)
H(x) 表示无向联通图个数,并且我们为每个图定一个根 考虑断掉根所在的若干个点双的所有边,我们搞出一个连通块的
E
G
F
EGF
EGF 再
exp
\text{exp}
exp 就可以得到若干个点双,考虑断掉点双内所有边后剩下的联通块个数就是点双大小(除根),于是我们定义
b
i
b_i
bi 为大小为
i
+
1
i+1
i+1 的点双的方案数,
B
(
x
)
B(x)
B(x) 为其
E
G
F
EGF
EGF,并有单个点双的贡献:
∑
i
≥
1
b
i
i
!
H
(
x
)
i
=
B
(
H
(
x
)
)
\sum_{i\ge 1}\frac{b_i}{i!}H(x)^i=B(H(x))
∑i≥1i!biH(x)i=B(H(x)) 所以有等式:
H
(
x
)
=
x
exp
B
(
H
(
x
)
)
H
(
x
)
exp
B
(
H
(
x
)
)
=
x
H(x)=x\exp{B(H(x))}\\ \frac{H(x)}{\exp B(H(x))}=x
H(x)=xexpB(H(x))expB(H(x))H(x)=x 知道
H
(
x
)
H(x)
H(x) 要求
B
(
x
)
B(x)
B(x),我们构造
H
(
x
)
H(x)
H(x) 的反函数
H
−
1
(
x
)
=
x
exp
B
(
x
)
H^{-1}(x)=\frac{x}{\exp B(x)}
H−1(x)=expB(x)x 那么有
B
(
x
)
=
ln
x
H
−
1
(
x
)
B(x)=\ln \frac{x}{H^{-1}(x)}
B(x)=lnH−1(x)x,如果令
G
(
x
)
=
ln
H
(
x
)
x
G(x)=\ln\frac{H(x)}{x}
G(x)=lnxH(x) 那么
G
(
H
−
1
(
x
)
)
=
B
(
x
)
G(H^{-1}(x))=B(x)
G(H−1(x))=B(x) 拉个朗日反演:
[
x
n
]
B
(
x
)
=
[
x
n
]
G
(
H
−
1
(
x
)
)
=
[
x
−
1
]
1
n
G
′
(
x
)
1
H
(
x
)
n
[x^n]B(x)=[x^n]G(H^{-1}(x))=[x^{-1}]\frac{1}{n}G'(x)\frac{1}{H(x)^n}
[xn]B(x)=[xn]G(H−1(x))=[x−1]n1G′(x)H(x)n1 那么我们可以在
S
log
(
S
)
S\log(S)
Slog(S) 的时间求出
F
(
x
)
=
∑
k
+
1
∈
S
b
k
k
!
x
k
F(x)=\sum_{k+1\in S}\frac{b_k}{k!}x^{k}
F(x)=∑k+1∈Sk!bkxk 再令
F
(
x
)
F(x)
F(x) 为答案的
E
G
F
EGF
EGF,按同样的方法可以得到
F
(
x
)
=
x
exp
B
(
F
(
x
)
)
F
(
x
)
exp
B
(
F
(
x
)
)
=
x
F(x)=x\exp B(F(x))\\ \frac{F(x)}{\exp B(F(x))}=x
F(x)=xexpB(F(x))expB(F(x))F(x)=x 构造
F
−
1
(
x
)
=
x
exp
B
(
x
)
F^{-1}(x)=\frac{x}{\exp B(x)}
F−1(x)=expB(x)x,那么
[
x
n
]
F
(
x
)
=
[
x
−
1
]
1
n
1
(
F
−
1
(
x
)
)
n
=
[
x
n
−
1
]
1
n
exp
(
n
B
(
x
)
)
[x^n]F(x)=[x^{-1}]\frac{1}{n}\frac{1}{(F^{-1}(x))^n}=[x^{n-1}]\frac{1}{n}\exp (nB(x))
[xn]F(x)=[x−1]n1(F−1(x))n1=[xn−1]n1exp(nB(x))
#include<bits/stdc++.h>
#define cs const
#define poly vector<int>
#define pb push_back
using namespace std;
cs int N = 1e5+50, M = 1<<18|5;
cs int Mod = 998244353;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod: a + b;}int dec(int a, int b){ return a - b < 0 ? a - b + Mod: a - b;}int mul(int a, int b){ return 1ll * a * b % Mod;}int ksm(int a, int b){ int as=1;for(;b;b>>=1,a=mul(a,a))if(b&1) as=mul(as,a); return as;}void Add(int &a, int b){ a = add(a, b);}void Dec(int &a, int b){ a = dec(a, b);}void Mul(int &a, int b){ a = mul(a, b);}
int iv[M], fac[N], ifac[N];
cs int C=18;
poly w[C+1];
poly F;
poly H; // 无向连通图 with root
poly G; // 构造函数
poly T; // cooperate with G
poly A; // 点双内部连边个数
int n, m;
int up, bit; poly rev;
void pre_work(int n){
fac[0]=fac[1]=ifac[0]=ifac[1]=1;for(int i=2; i<=n; i++)
fac[i]=mul(fac[i-1],i), ifac[i]=mul(ifac[i-1],iv[i]);}void NTT_init(){for(int i=1; i<=C; i++) w[i].resize(1<<(i-1));
int wn=ksm(3,(Mod-1)/(1<<C)); w[C][0]=1;for(int i=1; i<(1<<(C-1)); i++) w[C][i]=mul(w[C][i-1],wn);for(int i=C-1;i;i--)for(int j=0;j<(1<<(i-1));j++) w[i][j]=w[i+1][j<<1];
iv[0]=iv[1]=1;for(int i=2; i<=(1<<C); i++) iv[i]=mul(Mod-Mod/i,iv[Mod%i]);}void init(int deg){
up=1; bit=0;while(up<deg) up<<=1,++bit; rev.resize(up);for(int i=0; i<up; i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));}void NTT(poly &a, int typ=1){for(int i=0; i<up; i++)if(i<rev[i])swap(a[i],a[rev[i]]);for(int i=1,l=1;i<up;i<<=1,++l)for(int j=0; j<up; j+=(i<<1))for(int k=0; k<i; k++){
int x=a[k+j], y=mul(w[l][k],a[k+j+i]);
a[k+j]=add(x,y); a[k+j+i]=dec(x,y);}if(typ==-1){reverse(a.begin()+1,a.end());for(int i=0; i<up; i++)Mul(a[i],iv[up]);}}poly operator * (poly a, poly b){
int deg=a.size()+b.size()-1;init(deg);
a.resize(up); b.resize(up);NTT(a);NTT(b);for(int i=0; i<up; i++)Mul(a[i],b[i]);NTT(a,-1); a.resize(deg); return a;}poly inv(poly a, int deg){
poly b(1,ksm(a[0],Mod-2)),c;for(int lim=4;lim<(deg<<2);lim<<=1){
c.resize(lim>>1);init(lim);for(int i=0; i<(lim>>1); i++) c[i]=i<(int)a.size()?a[i]:0;
c.resize(up); b.resize(up);NTT(c);NTT(b);for(int i=0; i<lim; i++)Mul(b[i],dec(2,mul(b[i],c[i])));NTT(b,-1); b.resize(lim>>1);} b.resize(deg); return b;}poly deriv(poly a){for(int i=0; i+1<(int)a.size(); i++) a[i]=mul(i+1,a[i+1]);
a.pop_back(); return a;}poly integ(poly a){
a.pb(0);for(int i=a.size()-1;i;i--) a[i]=mul(iv[i],a[i-1]);
a[0]=0; return a;}poly ln(poly a, int deg=-1){if(deg==-1) deg=a.size();
a=integ(deriv(a)*inv(a,deg)); a.resize(deg); return a;}poly Exp(poly a, int deg=-1){if(deg==-1) deg = a.size(); poly b(1,1), c;for(int lim=2; lim<(deg<<1); lim<<=1){
c=ln(b,lim);Dec(c[0],1);for(int i=0; i<lim; i++) c[i]=dec(i<(int)a.size()?a[i]:0,c[i]);
b=b*c; b.resize(lim);} b.resize(deg); return b;}void work_F(){
F.resize(n+2);for(int i=0; i<(int)F.size(); i++)
F[i]=mul(ifac[i],ksm(2,(1ll*i*(i-1)/2)%(Mod-1)));
H=ln(F);for(int i=0; i<(int)H.size(); i++)Mul(H[i],i);
G=H;for(int i=1; i<(int)G.size(); i++) G[i-1]=G[i];
T=G; G=deriv(ln(G)); T=ln(T);}int work(int x){
poly a(x,0), b(x,0);for(int i=0; i<x; i++) a[i]=G[i], b[i]=T[i];for(int i=0; i<(int)b.size(); i++)Mul(b[i],Mod-x);
b=a*Exp(b); return mul(iv[x],b[x-1]);}int work_ans(){for(int i=0; i<(int)A.size(); i++)Mul(A[i],n);
A=Exp(A); return mul(A[n-1],mul(fac[n-1],iv[n]));}int main(){
cin>>n>>m;
NTT_init(); pre_work(n+5);
work_F(); A.resize(n+1);for(int i=1,x; i<=m; i++)scanf("%d",&x), --x, A[x]=work(x);
cout << work_ans(); return 0;}