题意
从有哈密尔顿回路的竞赛图中随机选取一张,图上哈密尔顿回路数的期望是多少,如果没有这样的竞赛图,输出-1,mod 998244353
数据
给定n,表示竞赛图的点数,需要对从1到n的每个值都计算一次
n
≤
1
e
5
n\le 1e5
n≤1e5
解法
考虑知道n个点的竞赛图中总共有多少条哈密尔顿回路,首先需要一个n个点的环排列,方案数是
(
n
−
1
)
!
(n-1)!
(n−1)!,然后剩下来的边随便连,这是
2
n
∗
(
n
−
1
)
/
2
−
n
2^{n*(n-1)/2-n}
2n∗(n−1)/2−n,这个是每条边有两个方向,然后需要知道n个点的竞赛图中有多少个图存在哈密尔顿回路,设为f[n]
那么答案就是
(
n
−
1
)
!
∗
2
n
∗
(
n
−
1
)
/
2
−
n
f
[
n
]
\frac{(n-1)!*2^{n*(n-1)/2-n}}{f[n]}
f[n](n−1)!∗2n∗(n−1)/2−n
现在的问题是求f[n]的值,考虑用总数减去不合法的方案数:
f
[
n
]
=
2
C
(
n
,
2
)
−
∑
i
=
1
n
−
1
f
[
i
]
∗
C
(
n
,
i
)
∗
2
C
(
n
−
i
,
2
)
f[n]=2^{C(n,2)}-\sum_{i=1}^{n-1}f[i]*C(n,i)*2^{C(n-i,2)}
f[n]=2C(n,2)−∑i=1n−1f[i]∗C(n,i)∗2C(n−i,2)
这个式子的前半部分是n个点的竞赛图总数,后面计算的方式是枚举一号点所在的合法联通块的大小,此时为了保证这个方案不合法,其他点向这个联通块连边的方式是固定的,其它的点之间可以随便连。
观察f[n]的式子,由于里面出现了组合数,考虑EGF,把组合数拆开:
f
[
n
]
=
2
C
(
n
,
2
)
−
∑
i
=
1
n
−
1
f
[
i
]
∗
n
!
i
!
∗
(
n
−
i
)
!
∗
2
C
(
n
−
i
,
2
)
f[n]=2^{C(n,2)}-\sum_{i=1}^{n-1}f[i]*\frac{n!}{i!*(n-i)!}*2^{C(n-i,2)}
f[n]=2C(n,2)−∑i=1n−1f[i]∗i!∗(n−i)!n!∗2C(n−i,2)
我们把
1
i
!
\frac{1}{i!}
i!1和
f
[
i
]
f[i]
f[i]放到一起,
1
(
n
−
i
!
)
\frac{1}{(n-i!)}
(n−i!)1和
2
C
(
n
−
i
,
2
)
2^{C(n-i,2)}
2C(n−i,2)放到一起,再两遍同时除以
n
!
n!
n!,就可以写出两个EGF
F
(
x
)
=
∑
f
[
n
]
i
!
x
i
,
G
(
x
)
=
∑
2
C
(
i
,
2
)
i
!
x
i
F(x)=\sum \frac{f[n]}{i!}x^i,G(x)=\sum \frac{2^{C(i,2)}}{i!}x^i
F(x)=∑i!f[n]xi,G(x)=∑i!2C(i,2)xi
这样我们接着处理刚才的式子:
2
C
(
n
,
2
)
=
f
[
n
]
+
∑
i
=
1
n
−
1
f
[
i
]
∗
n
!
i
!
∗
(
n
−
i
)
!
∗
2
C
(
n
−
i
,
2
)
2^{C(n,2)}=f[n]+\sum_{i=1}^{n-1}f[i]*\frac{n!}{i!*(n-i)!}*2^{C(n-i,2)}
2C(n,2)=f[n]+∑i=1n−1f[i]∗i!∗(n−i)!n!∗2C(n−i,2)
2
C
(
n
,
2
)
=
∑
i
=
1
n
f
[
i
]
n
!
i
!
∗
(
n
−
i
)
!
∗
2
C
(
n
−
i
,
2
)
2^{C(n,2)}=\sum_{i=1}^{n}f[i]\frac{n!}{i!*(n-i)!}*2^{C(n-i,2)}
2C(n,2)=∑i=1nf[i]i!∗(n−i)!n!∗2C(n−i,2)
G
(
x
)
=
F
(
x
)
G
(
x
)
+
1
,
此
处
的
+
1
是
因
为
i
=
0
的
时
候
不
满
足
递
推
式
,
所
以
要
加
一
个
常
数
调
整
一
下
G(x)=F(x)G(x)+1,此处的+1是因为i=0的时候不满足递推式,所以要加一个常数调整一下
G(x)=F(x)G(x)+1,此处的+1是因为i=0的时候不满足递推式,所以要加一个常数调整一下
F
(
x
)
=
1
−
1
G
(
x
)
F(x)=1-\frac{1}{G(x)}
F(x)=1−G(x)1
多项式求逆求出F(x),就可以解决问题,记得处理好爆int的问题,实在不行就开longlong
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
const int maxn=1e6+5;
inline int read(){
char c=getchar();int t=0,f=1;
while((!isdigit(c))&&(c!=EOF)){if(c=='-')f=-1;c=getchar();}
while((isdigit(c))&&(c!=EOF)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
return t*f;
}
int n,fac[maxn],inv[maxn];
inline int ksm(int a,int b){
int ans=1;
while(b){
if(b&1)ans=1ll*ans*a%mod;
a=1ll*a*a%mod;b>>=1;
}
return ans;
}
int g[maxn],r[maxn];
inline int am(int x){
if(x>=mod)return x-mod;
return x;
}
inline void fft(int a[],int lim,int f){
for(int i=1;i<lim;i++)if(i<r[i])swap(a[i],a[r[i]]);
for(int i=1;i<lim;i<<=1){
int wn=ksm(3,(mod-1)/(i<<1));
if(f==-1)wn=ksm(wn,mod-2);
for(int j=0;j<lim;j+=(i<<1)){
int wt=1;
for(int k=0;k<i;k++,wt=1ll*wt*wn%mod){
int x=a[j+k],y=1ll*a[j+k+i]*wt%mod;
a[j+k]=am(x+y);a[j+k+i]=am(x-y+mod);
}
}
}
if(f==-1){
int inv=ksm(lim,mod-2);
for(int i=0;i<lim;i++)a[i]=1ll*a[i]*inv%mod;
}
}
int lim,l,c[maxn];
int f[maxn];
void getinv(int a[],int b[],int n){
if(n==1){
b[0]=ksm(a[0],mod-2);return ;
}
getinv(a,b,(n+1)>>1);
lim=1,l=0;
while(lim<=(n+n))lim<<=1,l++;
for(int i=1;i<lim;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
for(int i=0;i<n;i++)c[i]=a[i];
for(int i=n;i<lim;i++)c[i]=0;
fft(c,lim,1);fft(b,lim,1);
for(int i=0;i<lim;i++)b[i]=1ll*am(2-1ll*c[i]*b[i]%mod+mod)*b[i]%mod;
fft(b,lim,-1);
for(int i=n;i<lim;i++)b[i]=0;
}
signed main(){
n=read();
fac[0]=inv[0]=1;
for(int i=1;i<=n;i++)fac[i]=1ll*fac[i-1]*i%mod;
inv[n]=ksm(fac[n],mod-2);
for(int i=n-1;i>=1;i--)inv[i]=1ll*inv[i+1]*(i+1)%mod;
for(int i=0;i<=n;i++)g[i]=ksm(2,(i*(i-1)/2)%(mod-1));
for(int i=0;i<=n;i++){
g[i]=1ll*g[i]*inv[i]%mod;
}
getinv(g,f,n+1);
for(int i=0;i<=n;i++){
f[i]=am(mod-f[i]);
}
f[0]=am(f[0]+1);
for(int i=0;i<=n;i++)f[i]=1ll*f[i]*fac[i]%mod;
if(n>=1)puts("1");
if(n>=2)puts("-1");
for(int i=3;i<=n;i++)
printf("%d\n",1ll*fac[i-1]*ksm(2,1ll*i*(i-3)/2%(mod-1))%mod*ksm(f[i],mod-2)%mod);
return 0;
}