考虑先求两个东西:
一个是所有竞赛图的哈密顿回路个数
一个是存在哈密顿回路的竞赛图个数
第一个,考虑一个哈密顿回路,有 ( n − 1 ) ! (n-1)! (n−1)! 种走法,对每一种走法统计它出现多少次,其它边随便填,那么个数就是 ( n − 1 ) ! ∗ 2 ( n 2 ) − n (n-1)!*2^{\binom{n}{2}-n} (n−1)!∗2(2n)−n
第二个,发现如果存在哈密顿回路的话一定只有一个强连通分量
那么问题转换为统计大小为 n n n 的强联通分量的个数
枚举任意一个点的强连通分量大小,容斥
f ( n ) = 2 ( n 2 ) − ∑ i = 1 n − 1 f ( i ) ∗ ( n i ) ∗ 2 ( n − i 2 ) f(n)=2^{\binom{n}{2}}-\sum_{i=1}^{n-1}f(i)*\binom{n}{i}*2^{\binom{n-i}{2}} f(n)=2(2n)−i=1∑n−1f(i)∗(in)∗2(2n−i)
令
g
(
n
)
=
2
(
n
2
)
g(n)=2^{\binom{n}{2}}
g(n)=2(2n)
那么有
f
(
n
)
n
!
=
g
(
n
)
n
!
−
∑
i
=
1
n
−
1
f
(
i
)
i
!
∗
g
(
n
−
i
)
(
n
−
i
)
!
\frac{f(n)}{n!}=\frac{g(n)}{n!}-\sum_{i=1}^{n-1}\frac{f(i)}{i!}*\frac{g(n-i)}{(n-i)!}
n!f(n)=n!g(n)−i=1∑n−1i!f(i)∗(n−i)!g(n−i)
分治 N T T NTT NTT 即可
也可以多项式求逆,发现 f ( 0 ) = 0 , g ( 0 ) = 1 f(0)=0,g(0)=1 f(0)=0,g(0)=1,注意一下常数项,有
G = F ∗ G + 1 ⇔ F = 1 − 1 G G=F*G+1\Leftrightarrow F=1-\frac{1}{G} G=F∗G+1⇔F=1−G1
#include<bits/stdc++.h>
#define cs const
using namespace std;
cs int N = 1e5 + 5;
#define poly vector<int>
cs int Mod = 998244353;
typedef long long ll;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b;}
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Add(int &a, int b){ a = add(a, b); }
int ksm(int a, int b){ int ans = 1; for(;b;b>>=1,a=mul(a,a)) if(b&1) ans = mul(ans, a); return ans; }
int fac[N], ifac[N], n;
poly F, G;
cs int C = 19;
poly w[C+1]; int up, bit; poly rev;
void prework(){
for(int i = 1; i <= C; i++) w[i].resize(1 << i-1);
int wn = ksm(3, (Mod-1)/(1<<C)); w[C][0] = 1;
for(int i = 1; i < (1<<C-1); i++) w[C][i] = mul(w[C][i-1], wn);
for(int i = C-1; i; i--) for(int j = 0; j < (1<<i-1); j++) w[i][j] = w[i+1][j<<1];
}
void init(int len){
up = 1, bit = 0; while(up < len) up <<= 1, ++bit; rev.resize(up);
for(int i = 0; i < up; i++) rev[i] = (rev[i>>1]>>1)|((i&1)<<(bit-1));
}
void NTT(poly &a, int typ){
for(int i = 0; i < up; i++) if(i < rev[i]) swap(a[i], a[rev[i]]);
for(int i = 1, l = 1; i < up; i <<= 1, ++l)
for(int j = 0; j < up; j += (i<<1))
for(int k = 0; k < i; k++){
int x = a[k + j], y = mul(w[l][k], a[k + j + i]);
a[k + j] = add(x, y); a[k + j + i] = dec(x, y);
} if(typ == -1){
reverse(a.begin() + 1, a.end());
for(int i = 0, inv = ksm(up, Mod-2); i < up; i++) a[i] = mul(a[i], inv);
}
}
poly operator * (poly a, poly b){
int deg = a.size() + b.size() - 1; init(deg);
a.resize(up); b.resize(up); NTT(a, 1); NTT(b, 1);
for(int i = 0; i < up; i++) a[i] = mul(a[i], b[i]);
NTT(a, -1); a.resize(deg); return a;
}
void Solve(int l, int r){
if(l == r){ if(l) F[l] = dec(G[l], F[l]); return; }
int mid = (l+r) >> 1;
Solve(l, mid); poly A, B;
for(int i = l; i <= mid; i++) A.push_back(F[i]);
for(int i = l; i <= r; i++) B.push_back(G[B.size()]);
A = A * B;
for(int i = mid+1; i <= r; i++) Add(F[i], A[i - l]);
Solve(mid+1, r);
}
int main(){
prework();
cin >> n; fac[0] = ifac[0] = fac[1] = ifac[1] = 1;
for(int i = 2; i <= n; i++) fac[i] = mul(fac[i-1], i);
ifac[n] = ksm(fac[n], Mod-2);
for(int i = n-1; i >= 2; i--) ifac[i] = mul(ifac[i+1], i+1);
G.resize(n + 1); F.resize(n + 1);
for(int i = 0; i <= n; i++) G[i] = mul(ifac[i], ksm(2, ((ll)i*(i-1)/2) % (Mod-1)));
Solve(0, n);
if(n>=1) puts("1");
if(n>=2) puts("-1");
for(int i = 3; i <= n; i++){
int S1 = mul(fac[i - 1], ksm(2, ((ll)i*(i-1)/2 - i) % (Mod-1)));
int S2 = mul(F[i], fac[i]);
cout << mul(S1, ksm(S2, Mod-2)) << '\n';
} return 0;
}