题目
点双
一个点可以属于多个点双
记有根无向连通图的指数型生成函数为
D
(
x
)
D(x)
D(x),有根点双的指数型生成函数为
B
(
x
)
B(x)
B(x)
注意
d
0
=
0
d_0=0
d0=0,因为有根
考虑包含根的一个点双
这个点双内的每个点都可以向外连出一个无向连通图,但是不能连回来(否则也属于这个点双)
为什么不用考虑根连出去的无向图
其实是定义的问题,因为两个点也算作一个点双
也就是
∑
i
=
1
∞
b
i
+
1
D
i
(
x
)
i
!
\sum_{i=1}^\infty b_{i+1}\frac{D^i(x)}{i!}
i=1∑∞bi+1i!Di(x)
为什么要除以
i
!
i!
i! 因为
b
i
+
1
b_{i+1}
bi+1 本身已经让
i
+
1
i+1
i+1 个点方案有序,那么之后乘
n
!
n!
n! 就可以视作重排列(这
i
i
i 个点颜色一样)
然后直接来
D
(
x
)
=
x
e
∑
i
=
1
∞
b
i
+
1
D
i
(
x
)
i
!
D(x)=xe^{\sum_{i=1}^\infty b_{i+1}\frac{D^i(x)}{i!}}
D(x)=xe∑i=1∞bi+1i!Di(x)
那么就是
D
(
x
)
=
x
×
e
x
p
B
′
(
D
(
x
)
)
D(x)=x\times exp\ B'(D(x))
D(x)=x×exp B′(D(x))
现在要求
B
′
(
x
)
B'(x)
B′(x)
变形得到
l
n
D
(
x
)
x
=
B
′
(
D
(
x
)
)
ln\frac{D(x)}{x}=B'(D(x))
lnxD(x)=B′(D(x))
令
G
(
x
)
=
l
n
D
(
x
)
x
G(x)=ln\frac{D(x)}{x}
G(x)=lnxD(x)
那么
B
′
(
D
(
x
)
)
=
G
(
x
)
B'(D(x))=G(x)
B′(D(x))=G(x)
拉格朗日反演有拓展形式当
F
(
G
(
x
)
)
=
H
(
x
)
F(G(x))=H(x)
F(G(x))=H(x) 时候,有:
[
x
n
]
F
(
x
)
=
1
n
[
x
n
−
1
]
H
′
(
x
)
(
x
G
(
x
)
)
n
[x^n]F(x)=\frac{1}{n}[x^{n-1}]H'(x)(\frac{x}{G(x)})^n
[xn]F(x)=n1[xn−1]H′(x)(G(x)x)n
[ x n ] B ′ ( x ) = 1 n [ x n − 1 ] G ′ ( x ) ( x D ( x ) ) n [x^n]B'(x)=\frac{1}{n}[x^{n-1}]G'(x)(\frac{x}{D(x)})^n [xn]B′(x)=n1[xn−1]G′(x)(D(x)x)n
算就行了
但是我们要取第
n
−
1
n-1
n−1 项,因为求了导,而且还是有根的
也就是
b
n
−
2
∗
n
!
/
n
b_{n-2}*n!/n
bn−2∗n!/n
n
=
1
n=1
n=1 特判
边双
一个点可以属于一个边双
记有根无向连通图的指数型生成函数为
D
(
x
)
D(x)
D(x),有根边双的指数型生成函数为
B
(
x
)
B(x)
B(x)
注意
d
0
=
0
d_0=0
d0=0,因为有根
考虑包含根的边双:
枚举边双大小后连接一个连通图,也就是
i
D
(
x
)
iD(x)
iD(x)
可以想象成球上插羽毛
D
(
x
)
=
∑
i
=
1
+
∞
b
i
e
i
D
(
x
)
i
!
x
i
D(x)=\sum_{i=1}^{+\infty}b_i\frac{e^{iD(x)}}{i!}x^i
D(x)=i=1∑+∞bii!eiD(x)xi
此时不用再乘
x
x
x 了,因为已经枚举了根的
x
x
x
也就是
D
(
x
)
=
B
(
e
D
(
x
)
)
D(x)=B(e^{D(x)})
D(x)=B(eD(x))
拉格朗日反演有拓展形式当
F
(
G
(
x
)
)
=
H
(
x
)
F(G(x))=H(x)
F(G(x))=H(x) 时候,有:
[
x
n
]
F
(
x
)
=
1
n
[
x
n
−
1
]
H
′
(
x
)
(
x
G
(
x
)
)
n
[x^n]F(x)=\frac{1}{n}[x^{n-1}]H'(x)(\frac{x}{G(x)})^n
[xn]F(x)=n1[xn−1]H′(x)(G(x)x)n
[
x
n
]
B
(
x
)
=
1
n
[
x
n
−
1
]
D
′
(
x
)
(
x
e
D
(
x
)
)
n
[x^n]B(x)=\frac{1}{n}[x^{n-1}]D'(x)(\frac{x}{e^{D(x)}})^n
[xn]B(x)=n1[xn−1]D′(x)(eD(x)x)n
求完以后:
是
b
n
∗
n
!
/
n
b_n*n!/n
bn∗n!/n
代码
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<stack>
#include<ctime>
#include<cstdio>
#include<queue>
#include<cmath>
#include<vector>
#include<cstring>
#include<climits>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
inline int read(){
int f=1,x=0;char c=getchar();
while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
return f*x;
}
#define MAXN int(4e5)
#define INF 0x3f3f3f3f
const int Mod=998244353,g=3,rg=332748118;
inline int Mul(register LL x,register int y){
x*=y;
return x>=Mod?x%Mod:x;
}
inline int Add(register int x,register int y){
x+=y;
return x>=Mod?x-Mod:x;
}
inline int Pow(register int x,register LL y){
register int ret=1;
while(y){
if(y&1) ret=Mul(ret,x);
x=Mul(x,x),y>>=1;
}
return ret;
}
int rev[MAXN+5];
int pg[MAXN+5],prg[MAXN+5];
int fac[MAXN+5],ifac[MAXN+5],inv[MAXN+5];
inline int Len(register int n){
register int len,lg2;
for(len=1,lg2=0;len<n;len<<=1)
lg2++;
for(register int i=1;i<=len;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg2-1));
return len;
}
inline void NTT(int *A,int len,register int sign){
for(register int i=0;i<len;i++)
if(i<rev[i]) swap(A[i],A[rev[i]]);
for(register int k=1;k<len;k<<=1){
register int w0=(sign==1?pg[k]:prg[k]);
for(register int j=0,siz=k<<1;j<len;j+=siz)
for(register int i=0,w=1;i<k;i++,w=Mul(w,w0)){
register int x=A[i+j],y=Mul(w,A[i+j+k]);
A[i+j]=Add(x,y),A[i+j+k]=Add(x,Mod-y);
}
}
if(sign==-1){
register int Inv=Pow(len,Mod-2);
for(register int i=0;i<len;i++)
A[i]=Mul(A[i],Inv);
}
return ;
}
int tmp1[MAXN+5],tmp2[MAXN+5];
inline void Poly_Mul(register int *A,register int*B,register int*C,register int n,register int m){//A,B,C均可不清空
copy(A,A+n,tmp1),copy(B,B+m,tmp2);
register int len=Len(n+m-1);
fill(tmp1+n,tmp1+len,0),fill(tmp2+m,tmp2+len,0);
NTT(tmp1,len,1),NTT(tmp2,len,1);
for(int i=0;i<len;i++)
C[i]=Mul(tmp1[i],tmp2[i]);
NTT(C,len,-1);
return ;
}
int tmp3[MAXN+5];
inline void Poly_Inv(int *A,int *B,register int n){//B要清空
if(n==1){
B[0]=Pow(A[0],Mod-2);
return ;
}
Poly_Inv(A,B,(n+1)/2);
register int len=Len(2*n);
copy(A,A+n,tmp3);
fill(tmp3+n,tmp3+len,0),fill(B+n,B+len,0);
NTT(tmp3,len,1),NTT(B,len,1);
for(int i=0;i<len;i++)
B[i]=1ll*(2+Mod-1ll*B[i]*tmp3[i]%Mod)%Mod*B[i]%Mod;
NTT(B,len,-1),fill(B+n,B+len,0);
return ;
}
inline void Poly_Deriv(int *A,int *B,register int n){
for(register int i=1;i<n;i++)
B[i-1]=Mul(A[i],i);
B[n-1]=0;
return ;
}
inline void Poly_Inter(int *A,int *B,register int n){//有取模
for(register int i=n-1;i>=1;i--)
B[i]=Mul(A[i-1],inv[i]);
B[0]=0;
return ;
}
int inva[MAXN+5],da[MAXN+5];
inline void Poly_Ln(int *A,int *B,register int n){
Poly_Inv(A,inva,n);
Poly_Deriv(A,da,n);
Poly_Mul(inva,da,B,n,n);
Poly_Inter(B,B,n);
return ;
}
int cF[MAXN+5];
inline void Poly_Exp(int *A,int *B,int n){
if(n==1){
B[0]=1;
return ;
}
Poly_Exp(A,B,(n+1)/2),Poly_Ln(B,cF,n);
cF[0]=(1+A[0]-cF[0]+Mod)%Mod;
for(int i=1;i<n;i++)
cF[i]=(A[i]-cF[i]+Mod)%Mod;
int len=Len(2*n);
fill(cF+n,cF+len,0),fill(B+n,B+len,0);
NTT(cF,len,1),NTT(B,len,1);
for(int i=0;i<len;i++)
B[i]=1ll*B[i]*cF[i]%Mod;
NTT(B,len,-1),fill(B+n,B+len,0);
return ;
}
int lna[MAXN+5];
inline void Poly_Pow(int *A,int *P,int k,int n){
Poly_Ln(A,lna,n);
for(int i=0;i<n;i++)
lna[i]=1ll*lna[i]*k%Mod;
Poly_Exp(lna,P,n);
return ;
}
void Print(int *A,int n){
for(int i=0;i<n;i++)
printf("%d ",A[i]);
puts("");
return ;
}
#define N 100003
int T[MAXN+5],F[MAXN+5],G[MAXN+5],f[MAXN+5],P[MAXN+5],Ans[MAXN+5];
int main(){
fac[0]=1;
for(register int k=1;k<MAXN;k<<=1)
pg[k]=Pow(g,(Mod-1)/(k<<1)),prg[k]=Pow(rg,(Mod-1)/(k<<1));
for(register int i=1;i<=N;i++)
fac[i]=1ll*fac[i-1]*i%Mod;
ifac[N]=Pow(fac[N],Mod-2);
for(register int i=N-1;i>=0;i--)
ifac[i]=1ll*ifac[i+1]*(i+1)%Mod;
inv[1]=1;
for(register int i=2;i<=N;i++)
inv[i]=1ll*(Mod-Mod/i)*inv[Mod%i]%Mod;
for(int t=1;t<=5;t++){
int n=read();
//if(n==1){
// puts("1");
// continue;
//}
for(int i=0;i<n+3;i++)
T[i]=1ll*Pow(2,1ll*i*(i-1)/2%(Mod-1))*ifac[i]%Mod;
fill(F,F+n+3,0);
fill(G,G+n+3,0);
fill(f,f+n+3,0);
fill(P,P+n+3,0);
Poly_Ln(T,F,n+3);
for(int i=0;i<=n+1;i++)
F[i]=1ll*F[i+1]*(i+1)%Mod;
F[n+2]=0;
Poly_Ln(F,G,n+3);
Poly_Deriv(G,G,n+3);
Poly_Ln(F,f,n+3);
for(int i=0;i<n+3;i++)
f[i]=1ll*f[i]*(Mod-(n-1))%Mod;
Poly_Exp(f,P,n+3);
Poly_Mul(P,G,Ans,n+3,n+3);
int ans=1ll*Ans[n-2]*inv[n-1]%Mod*fac[n-1]%Mod;
printf("%d\n",ans);
}
return 0;
}
//
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<stack>
#include<ctime>
#include<cstdio>
#include<queue>
#include<cmath>
#include<vector>
#include<cstring>
#include<climits>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
inline int read(){
int f=1,x=0;char c=getchar();
while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
return f*x;
}
#define MAXN int(4e5)
#define INF 0x3f3f3f3f
const int Mod=998244353,g=3,rg=332748118;
inline int Mul(register LL x,register int y){
x*=y;
return x>=Mod?x%Mod:x;
}
inline int Add(register int x,register int y){
x+=y;
return x>=Mod?x-Mod:x;
}
inline int Pow(register int x,register LL y){
register int ret=1;
while(y){
if(y&1) ret=Mul(ret,x);
x=Mul(x,x),y>>=1;
}
return ret;
}
int rev[MAXN+5];
int pg[MAXN+5],prg[MAXN+5];
int fac[MAXN+5],ifac[MAXN+5],inv[MAXN+5];
inline int Len(register int n){
register int len,lg2;
for(len=1,lg2=0;len<n;len<<=1)
lg2++;
for(register int i=1;i<=len;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg2-1));
return len;
}
inline void NTT(int *A,int len,register int sign){
for(register int i=0;i<len;i++)
if(i<rev[i]) swap(A[i],A[rev[i]]);
for(register int k=1;k<len;k<<=1){
register int w0=(sign==1?pg[k]:prg[k]);
for(register int j=0,siz=k<<1;j<len;j+=siz)
for(register int i=0,w=1;i<k;i++,w=Mul(w,w0)){
register int x=A[i+j],y=Mul(w,A[i+j+k]);
A[i+j]=Add(x,y),A[i+j+k]=Add(x,Mod-y);
}
}
if(sign==-1){
register int Inv=Pow(len,Mod-2);
for(register int i=0;i<len;i++)
A[i]=Mul(A[i],Inv);
}
return ;
}
int tmp1[MAXN+5],tmp2[MAXN+5];
inline void Poly_Mul(register int *A,register int*B,register int*C,register int n,register int m){//A,B,C均可不清空
copy(A,A+n,tmp1),copy(B,B+m,tmp2);
register int len=Len(n+m-1);
fill(tmp1+n,tmp1+len,0),fill(tmp2+m,tmp2+len,0);
NTT(tmp1,len,1),NTT(tmp2,len,1);
for(int i=0;i<len;i++)
C[i]=Mul(tmp1[i],tmp2[i]);
NTT(C,len,-1);
return ;
}
int tmp3[MAXN+5];
inline void Poly_Inv(int *A,int *B,register int n){//B要清空
if(n==1){
B[0]=Pow(A[0],Mod-2);
return ;
}
Poly_Inv(A,B,(n+1)/2);
register int len=Len(2*n);
copy(A,A+n,tmp3);
fill(tmp3+n,tmp3+len,0),fill(B+n,B+len,0);
NTT(tmp3,len,1),NTT(B,len,1);
for(int i=0;i<len;i++)
B[i]=1ll*(2+Mod-1ll*B[i]*tmp3[i]%Mod)%Mod*B[i]%Mod;
NTT(B,len,-1),fill(B+n,B+len,0);
return ;
}
inline void Poly_Deriv(int *A,int *B,register int n){
for(register int i=1;i<n;i++)
B[i-1]=Mul(A[i],i);
B[n-1]=0;
return ;
}
inline void Poly_Inter(int *A,int *B,register int n){//有取模
for(register int i=n-1;i>=1;i--)
B[i]=Mul(A[i-1],inv[i]);
B[0]=0;
return ;
}
int inva[MAXN+5],da[MAXN+5];
inline void Poly_Ln(int *A,int *B,register int n){
Poly_Inv(A,inva,n);
Poly_Deriv(A,da,n);
Poly_Mul(inva,da,B,n,n);
Poly_Inter(B,B,n);
return ;
}
int cF[MAXN+5];
inline void Poly_Exp(int *A,int *B,int n){
if(n==1){
B[0]=1;
return ;
}
Poly_Exp(A,B,(n+1)/2),Poly_Ln(B,cF,n);
cF[0]=(1+A[0]-cF[0]+Mod)%Mod;
for(int i=1;i<n;i++)
cF[i]=(A[i]-cF[i]+Mod)%Mod;
int len=Len(2*n);
fill(cF+n,cF+len,0),fill(B+n,B+len,0);
NTT(cF,len,1),NTT(B,len,1);
for(int i=0;i<len;i++)
B[i]=1ll*B[i]*cF[i]%Mod;
NTT(B,len,-1),fill(B+n,B+len,0);
return ;
}
int lna[MAXN+5];
inline void Poly_Pow(int *A,int *P,int k,int n){
Poly_Ln(A,lna,n);
for(int i=0;i<n;i++)
lna[i]=1ll*lna[i]*k%Mod;
Poly_Exp(lna,P,n);
return ;
}
void Print(int *A,int n){
for(int i=0;i<n;i++)
printf("%lld ",1ll*A[i]*fac[i]%Mod);
puts("");
return ;
}
#define N 100003
int C[MAXN+5],D[MAXN+5],Ds[MAXN+5],F[MAXN+5],E[MAXN+5],G[MAXN+5];
//D[i]:大小为i的无向连通图
int main(){
fac[0]=1;
for(register int k=1;k<MAXN;k<<=1)
pg[k]=Pow(g,(Mod-1)/(k<<1)),prg[k]=Pow(rg,(Mod-1)/(k<<1));
for(register int i=1;i<=N;i++)
fac[i]=1ll*fac[i-1]*i%Mod;
ifac[N]=Pow(fac[N],Mod-2);
for(register int i=N-1;i>=0;i--)
ifac[i]=1ll*ifac[i+1]*(i+1)%Mod;
inv[1]=1;
for(register int i=2;i<=N;i++)
inv[i]=1ll*(Mod-Mod/i)*inv[Mod%i]%Mod;
for(int t=1;t<=5;t++){
int n=read();
if(n==1){
puts("1");
continue;
}
fill(C,C+n+1,0);
fill(E,E+n+1,0);
fill(D,D+n+1,0);
fill(Ds,Ds+n+1,0);
for(int i=0;i<n+1;i++)
C[i]=1ll*Pow(2,1ll*i*(i-1)/2%(Mod-1))*ifac[i]%Mod;
Poly_Ln(C,D,n+1);
for(int i=0;i<n+1;i++)
D[i]=1ll*D[i]*i%Mod;
for(int i=0;i<n+1;i++)
F[i]=Mul(D[i],Mod-n);
Poly_Exp(F,E,n+1);
Poly_Deriv(D,Ds,n+1);
Poly_Mul(Ds,E,G,n+1,n+1);
int ans=1ll*G[n-1]*inv[n]%Mod*fac[n-1]%Mod;
printf("%d\n",ans);
}
return 0;
}
//