题意
给出n,求对于任意的
1≤i≤n
1
≤
i
≤
n
,求在所有i个点且有哈密顿回路的竞赛图中,哈密顿回路的期望数量是多少。答案模998244353
n≤105
n
≤
10
5
分析
所有竞赛图的哈密顿回路数量很好求,考虑每一条哈密顿路径的贡献,那么答案就是
(n−1)!∗2n(n−1)2−n
(
n
−
1
)
!
∗
2
n
(
n
−
1
)
2
−
n
。
现在考虑如何求有哈密顿回路的竞赛图数量。
首先有个结论,就是一个竞赛图存在哈密顿回路当且仅当其是一个强连通图。
证明:若其不是强连通图则显然没有哈密顿回路。若其是强连通图,考虑归纳。假设在当n=k时结论成立。那么当我们新加入一个点时,如果新的竞赛图也是强连通图,那么它向前k个点的连边中,必然存在两种方向不同的边,那么也就是在原来的哈密顿路径上,存在相邻的两个点A和B满足第k+1个点连向他们的边的方向不同。那么也就构成了一条新的哈密顿回路。
接下来考虑如何求n个点的强连通竞赛图数量。
设
f(n)
f
(
n
)
表示n个点的竞赛图数量,显然有
f(n)=2n(n−1)2
f
(
n
)
=
2
n
(
n
−
1
)
2
。设
g(n)
g
(
n
)
表示n个点的强连通竞赛图数量。
不难得到递推式
展开一下可以得到
设 F(n)=f(n)n!,G(n)=g(n)n! F ( n ) = f ( n ) n ! , G ( n ) = g ( n ) n ! ,那么有 G=F−GF G = F − G F ,画一下可以得到 G=FF+1 G = F F + 1 。
多项式求逆即可。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
typedef long long LL;
const int N=400005;
const int MOD=998244353;
int n,a[N],b[N],inv[N],rev[N],L,tmp[N],jc[N/4],ny[N/4];
int ksm(int x,int y)
{
int ans=1;
while (y)
{
if (y&1) ans=(LL)ans*x%MOD;
x=(LL)x*x%MOD;y>>=1;
}
return ans;
}
void NTT(int *a,int f)
{
for (int i=0;i<L;i++) if (i<rev[i]) std::swap(a[i],a[rev[i]]);
for (int i=1;i<L;i<<=1)
{
int wn=ksm(3,f==1?(MOD-1)/i/2:MOD-1-(MOD-1)/i/2);
for (int j=0;j<L;j+=(i<<1))
{
int w=1;
for (int k=0;k<i;k++)
{
int u=a[j+k],v=(LL)a[j+k+i]*w%MOD;
a[j+k]=(u+v)%MOD;a[j+k+i]=(u+MOD-v)%MOD;
w=(LL)w*wn%MOD;
}
}
}
int ny=ksm(L,MOD-2);
if (f==-1) for (int i=0;i<L;i++) a[i]=(LL)a[i]*ny%MOD;
}
void get_inv(int *a,int len)
{
if (len==1) {inv[0]=ksm(a[0],MOD-2);return;}
get_inv(a,len/2);
int lg=0;L=len*2;
for (int w=1;w<L;w<<=1,lg++);
for (int i=0;i<L;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1));
for (int i=0;i<len;i++) tmp[i]=a[i];
for (int i=len;i<L;i++) tmp[i]=0;
NTT(tmp,1);NTT(inv,1);
for (int i=0;i<L;i++) inv[i]=(inv[i]*2%MOD+MOD-(LL)tmp[i]*inv[i]%MOD*inv[i]%MOD)%MOD;
NTT(inv,-1);
for (int i=len;i<L;i++) inv[i]=0;
}
int main()
{
scanf("%d",&n);
jc[0]=jc[1]=ny[0]=ny[1]=1;
for (int i=2;i<=n;i++) jc[i]=(LL)jc[i-1]*i%MOD,ny[i]=(LL)(MOD-MOD/i)*ny[MOD%i]%MOD;
for (int i=2;i<=n;i++) ny[i]=(LL)ny[i-1]*ny[i]%MOD;
for (int i=1;i<=n;i++) a[i]=b[i]=(LL)ksm(2,(LL)i*(i-1)/2%(MOD-1))*ny[i]%MOD;
a[0]++;
for (L=1;L<=n;L<<=1);
get_inv(a,L);
int lg=0;
for (L=1;L<=n*2;L<<=1,lg++);
for (int i=0;i<L;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1));
for (int i=n+1;i<L;i++) inv[i]=0;
NTT(b,1);NTT(inv,1);
for (int i=0;i<L;i++) b[i]=(LL)b[i]*inv[i]%MOD;
NTT(b,-1);
for (int i=1;i<=n;i++) b[i]=(LL)b[i]*jc[i]%MOD;
printf("%d\n",1);
for (int i=2;i<=n;i++)
if (!b[i]) puts("-1");
else printf("%d\n",(LL)jc[i-1]*ksm(2,((LL)i*(i-1)/2%(MOD-1)+MOD-1-i)%(MOD-1))%MOD*ksm(b[i],MOD-2)%MOD);
return 0;
}