题目
点双
一个点可以属于多个点双
记有根无向连通图的指数型生成函数为
,有根点双的指数型生成函数为
注意
,因为有根
考虑包含根的一个点双
这个点双内的每个点都可以向外连出一个无向连通图,但是不能连回来(否则也属于这个点双)
为什么不用考虑根连出去的无向图
其实是定义的问题,因为两个点也算作一个点双
也就是
为什么要除以
因为
本身已经让
个点方案有序,那么之后乘
就可以视作重排列(这
个点颜色一样)
然后直接来
那么就是
现在要求
变形得到
令
那么
拉格朗日反演有拓展形式当
时候,有:
算就行了
但是我们要取第
项,因为求了导,而且还是有根的
也就是
特判
边双
一个点可以属于一个边双
记有根无向连通图的指数型生成函数为
,有根边双的指数型生成函数为
注意
,因为有根
考虑包含根的边双:
枚举边双大小后连接一个连通图,也就是
可以想象成球上插羽毛
此时不用再乘
了,因为已经枚举了根的
也就是
拉格朗日反演有拓展形式当
时候,有:
求完以后:
是
代码
#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;
}
//