Description
古明地恋(koishi)和ICG姉貴(ichigo_aneki)是好朋友。
给定集合S,请你求出n个点的“所有极大点双连通分量的大小都在S内”的不同简单无向连通图的个数对 998244353 取模的结果。
点双连通分量:删去任意一个点后剩下的点依然保持连通的连通子图。
极大点双连通分量:一个点双连通分量,且不存在更大的点双连通分量包含自己。
极大点双连通分量的大小:指连通分量包含的点数。
两个简单无向图不同,当且仅当存在某条边(u,v)出现在了其中一个无向图,而没有出现在另一个无向图。
ICG:「えっと、それじゃあ、問題背景をください」
NYN:「ないです。」
ICG:「やめたらこの仕事!!!」
NYN:「しょうがないな。。。」
n<=1e5,∑ai<=1e5
Solution
我能说我是通过这道题知道cookie☆的吗
首先我们求出H(x)表示x个点的有根联通图数量,这个很好求(bzoj3456)
然后我们考虑一个有根联通图的构成,删去根之后会剩下许多联通块
每个联通块里面都有一些和根在同一个点双中间的点,将这些点双的边删去会得到许多有根联通图。
设bi表示i+1个点的点双个数,枚举有多少个这样的点,那么单个联通块的贡献可以写成
∑
b
i
i
!
H
(
x
)
i
∑{bi\over i!}H(x)^i
∑i!biH(x)i记这个东西为B(H(x))
那么根据EGF的性质我们有对于整张图
H
(
x
)
=
x
e
B
(
H
(
x
)
)
H(x)=xe^{B(H(x))}
H(x)=xeB(H(x))
B
(
H
(
x
)
)
=
l
n
H
(
x
)
x
B(H(x))=ln{H(x)\over x}
B(H(x))=lnxH(x)
记
H
−
1
(
x
)
H^{-1}(x)
H−1(x)表示H(x)的符合逆(即
H
(
H
−
1
(
x
)
)
=
x
H(H^{-1}(x))=x
H(H−1(x))=x)
我们有
B
(
x
)
=
l
n
x
H
−
1
(
x
)
B(x)=ln {x\over H^{-1}(x)}
B(x)=lnH−1(x)x
直接用拉格朗日反演求B的复杂度无法承受我们需要另找其他方法
有个叫做扩展拉格朗日反演的东西
[
x
n
]
G
(
H
(
x
)
)
=
1
n
x
n
−
1
G
′
(
x
)
(
x
H
−
1
(
x
)
)
n
[x^n]G(H(x))={{1\over n}}x^{n-1}G'(x)({x\over H^{-1}(x)})^n
[xn]G(H(x))=n1xn−1G′(x)(H−1(x)x)n
考虑构造
G
(
H
−
1
(
x
)
)
=
B
(
x
)
G(H^{-1}(x))=B(x)
G(H−1(x))=B(x)
那么
G
(
x
)
=
l
n
H
(
x
)
x
G(x)=ln{H(x)\over x}
G(x)=lnxH(x)
G(x)是可以求出来的,进而可以用扩展拉格朗日反演求出每一个[x^n]B(x)
令
B
′
(
x
)
=
∑
i
−
1
∈
S
b
i
i
!
x
i
B'(x)=\sum_{i-1\in S}{bi\over i!x^i}
B′(x)=∑i−1∈Si!xibi
考虑答案的EGF F(x),根据上述推导有
F
(
x
)
=
x
e
B
′
(
F
(
x
)
)
F(x)=xe^{B'(F(x))}
F(x)=xeB′(F(x))
那么[x^n]F(x)可以用一次拉格朗日反演求出
终于写出来了
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
int read() {
char ch;
for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
int x=ch-'0';
for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x;
}
const int N=3e5+5,Mo=998244353;
ll pwr(ll x,ll y) {
ll z=1;
for(;y;y>>=1,x=x*x%Mo)
if (y&1) z=z*x%Mo;
return z;
}
ll W[2][N],fact[N],inv[N];
void init(int b){
for(int i=1;i<(1<<b);i<<=1){
ll wn=pwr(3,(Mo-1)/(i<<1));
for(int j=0;j<i;++j) W[1][i+j]=(j?wn*W[1][i+j-1]%Mo:1);
wn=pwr(3,Mo-1-(Mo-1)/(i<<1));
for(int j=0;j<i;++j) W[0][i+j]=(j?wn*W[0][i+j-1]%Mo:1);
}
int n=(1<<b)-1;
fact[0]=1;fo(i,1,n) fact[i]=fact[i-1]*i%Mo;
inv[n]=pwr(fact[n],Mo-2);fd(i,n-1,0) inv[i]=inv[i+1]*(i+1)%Mo;
}
void DFT(ll *a,int len,int flag) {
if (flag==-1) flag=0;
for(int i=0,j=0;i<len;++i){
if(i<j) swap(a[i],a[j]);
for(int k=len>>1;(j^=k)<k;k>>=1);
}
for(int i=1;i<len;i<<=1)
for(int j=0;j<len;j+=(i<<1))
for(int k=0;k<i;++k) {
ll x=a[j+k],y=a[j+k+i]*W[flag][i+k]%Mo;
a[j+k]=(x+y)%Mo;
a[j+k+i]=(x-y)%Mo;
}
ll inv=pwr(len,Mo-2);
if (!flag) for(int i=0;i<len;i++) a[i]=a[i]*inv%Mo;
}
ll c[N];
void get_Inv(ll *a,ll *b,int n) {
if (n==1) {b[0]=pwr(a[0],Mo-2);return;}
get_Inv(a,b,(n+1)>>1);
int len=1;
for(;len<n<<1;len<<=1);
fo(i,0,n-1) c[i]=a[i];fo(i,n,len-1) c[i]=0;
fo(i,(n+1)>>1,len-1) b[i]=0;
DFT(c,len,1);DFT(b,len,1);
fo(i,0,len-1) b[i]=(2*b[i]-b[i]*b[i]%Mo*c[i])%Mo;
DFT(b,len,-1);
fo(i,n,len-1) b[i]=0;
}
ll f[N],g[N];
void get_ln(ll *a,ll *b,int n) {
fo(i,0,n-2) f[i]=a[i+1]*(i+1)%Mo;f[n-1]=0;
get_Inv(a,g,n);
int len=n<<1;
fo(i,n,len-1) f[i]=g[i]=0;
DFT(f,len,1);DFT(g,len,1);
fo(i,0,len-1) f[i]=f[i]*g[i]%Mo;
DFT(f,len,-1);
fo(i,1,n-1) b[i]=f[i-1]*pwr(i,Mo-2)%Mo;
b[0]=0;
}
ll h[N];
void get_exp(ll *a,ll *b,int n) {
if (n==1) {b[0]=1;return;}
get_exp(a,b,n>>1);
get_ln(b,h,n);
fo(i,0,n-1) h[i]=(a[i]-h[i]+Mo)%Mo;
h[0]=(h[0]+1)%Mo;
int len=n<<1;
fo(i,n,len-1) h[i]=b[i]=0;
DFT(b,len,1);DFT(h,len,1);
fo(i,0,len-1) b[i]=h[i]*b[i]%Mo;
DFT(b,len,-1);
fo(i,n,len-1) b[i]=0;
}
ll p[N];
void get_pow(ll *a,int m,int n) {
get_ln(a,p,n);
fo(i,0,n-1) p[i]=p[i]*m%Mo;
get_exp(p,a,n);
}
int n,m,len;
ll F[N],G[N],H[N],A[N],B[N],C[N];
void get_H() {
fo(i,0,len-1) H[i]=pwr(2,(ll)i*(i-1)/2)*inv[i]%Mo;
get_ln(H,H,len);
fo(i,0,len-1) H[i]=H[i]*i%Mo;
}
void get_G() {
fo(i,0,len-1) G[i]=H[i+1];
get_ln(G,G,len);
fo(i,0,len-1) G[i]=G[i+1]*(i+1)%Mo;
G[len-1]=0;
}
ll get_B(int n) {
for(len=1;len<=n;len<<=1);
fo(i,0,len-1) F[i]=H[i]*(-n)%Mo;
get_exp(F,A,len);
fo(i,0,len-1) C[i]=G[i];
fo(i,len,len<<1) A[i]=C[i]=0;
len<<=1;
DFT(A,len,1);DFT(C,len,1);
fo(i,0,len-1) A[i]=A[i]*C[i]%Mo;
DFT(A,len,-1);
return A[n-1]*pwr(n,Mo-2)%Mo;
}
ll get_F(int n) {
for(len=1;len<=n;len<<=1);
fo(i,0,len-1) B[i]=B[i]*n%Mo;
get_exp(B,F,len);
return F[n-1]*pwr(n,Mo-2)%Mo*fact[n-1]%Mo;
}
int main() {
init(18);
n=read();m=read();
for(len=1;len<=n;len<<=1);
get_H();get_G();
fo(i,0,len-2) H[i]=H[i+1];H[len-1]=0;
get_ln(H,H,len);
fo(i,1,m) {
int x=read()-1;
B[x]=get_B(x);
}
printf("%lld\n",(get_F(n)+Mo)%Mo);
return 0;
}