链接
考虑所有竞赛图的哈密顿回路条数 n ! n 2 C n 2 − n \frac {n!} {n} 2^{C_{n}^{2}-n} nn!2Cn2−n,即选出一条哈密顿回路剩下的边任意连。
但题目中所求的是有哈密顿回路条数的竞赛图,即强联通的竞赛图。
设 f ( n ) f(n) f(n)表示点数为 n n n的强联通竞赛图数量。 g ( n ) g(n) g(n)表示点数为 n n n的竞赛图数量。得到
f ( n ) = g ( n ) − ∑ i = 1 n − 1 C n i f ( i ) g ( n − i ) f(n)=g(n)-\sum_{i=1}^{n-1}C_{n}^if(i)g(n-i) f(n)=g(n)−i=1∑n−1Cnif(i)g(n−i)
即枚举拓扑序最小的联通块,这部分没有出边,剩下的任意连边。
设 F ( i ) F(i) F(i)为 f ( i ) i ! \frac {f(i)} {i!} i!f(i)的生成函数, G ( i ) G(i) G(i)为 g ( i ) i ! \frac {g(i)} {i!} i!g(i)的生成函数,拆开组合数化解后
F ( x ) = G ( x ) G ( x ) + 1 F(x)=\frac {G(x)} {G(x)+1} F(x)=G(x)+1G(x)
多项式求逆即可。
#include
using namespace std;
typedef long long lint;
const int mod = 998244353;
const int maxn = 500005;
int m, n;
int fac[maxn], ifac[maxn], G[maxn], H[maxn], F[maxn];
inline int Pow(int x, int k)
{
int res = 1;
while (k) {
if (k & 1) res = (lint)res * x % mod;
x = (lint)x * x % mod; k >>= 1;
}
return res;
}
inline int gi()
{
char c = getchar();
while (c < '0' || c > '9') c = getchar();
int sum = 0;
while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
namespace poly
{
const int phi = mod - 1, G = 3;
int n, len, L, R[maxn], A[maxn], B[maxn];
void NTT(int *a, int f)
{
for (int i = 0; i < n; ++i) if (i < R[i]) swap(a[i], a[R[i]]);
for (int i = 1; i < n; i <<= 1) {
int wn = Pow(G, phi / (i << 1)), t;
if (f == -1) wn = Pow(wn, mod - 2);
for (int j = 0; j < n; j += (i << 1)) {
int w = 1;
for (int k = 0; k < i; ++k, w = (lint)w * wn % mod) {
t = (lint)a[j + i + k] * w % mod;
a[j + i + k] = a[j + k] - t;
if (a[j + i + k] < 0) a[j + i + k] += mod;
a[j + k] = a[j + k] + t;
if (a[j + k] >= mod) a[j + k] -= mod;
}
}
}
}
void mul(int *a, int *b, int len1, int len2, int *c, int len3)
{
for (L = 0, n = 1, len = len1 + len2 - 1; n < len; n <<= 1) ++L;
for (int i = 0; i < n; ++i) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
fill(A, A + n, 0); fill(B, B + n, 0);
for (int i = 0; i < len1; ++i) A[i] = a[i];
for (int i = 0; i < len2; ++i) B[i] = b[i];
NTT(A, 1); NTT(B, 1);
for (int i = 0; i < n; ++i) A[i] = (lint)A[i] * B[i] % mod;
NTT(A, -1);
int inv = Pow(n, mod - 2);
for (int i = 0; i < len3; ++i) c[i] = (lint)A[i] * inv % mod;
}
void mul(int *a, int *b, int len1, int *c, int len2)
{
for (L = 0, n = 1, len = len1 + len1 - 1; n < len; n <<= 1) ++L;
for (int i = 0; i < n; ++i) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
fill(A, A + n, 0); fill(B, B + n, 0);
for (int i = 0; i < len1; ++i) A[i] = a[i];
for (int i = 0; i < len2; ++i) B[i] = b[i];
NTT(A, 1); NTT(B, 1);
for (int i = 0; i < n; ++i) A[i] = (lint)A[i] * B[i] % mod * B[i] % mod;
NTT(A, -1);
int inv = Pow(n, mod - 2);
for (int i = 0; i < len2; ++i) c[i] = (lint)A[i] * inv % mod;
}
void poly_inv(int *a, int n, int *b)
{
static int c[maxn];
b[0] = Pow(a[0], mod - 2);
for (int t = 2; (t >> 1) < n; t <<= 1) {
for (int i = 0; i < t; ++i) c[i] = b[i];
mul(a, b, t, b, t);
for (int i = 0; i < t; ++i) b[i] = ((c[i] << 1ll) - b[i] + mod) % mod;
fill(c, c + t, 0);
}
}
}
int main()
{
m = gi();
for (n = 1; n <= m; n <<= 1) ;
fac[0] = ifac[0] = ifac[1] = 1;
for (int i = 2; i < n; ++i) ifac[i] = (lint)(mod - mod / i) * ifac[mod % i] % mod;
for (int i = 2; i < n; ++i) ifac[i] = (lint)ifac[i - 1] * ifac[i] % mod;
for (int i = 1; i < n; ++i) fac[i] = (lint)fac[i - 1] * i % mod;
for (int i = 1; i < n; ++i) G[i] = H[i] = (lint)Pow(2, ((lint)i * (i - 1) / 2) % (mod - 1)) * ifac[i] % mod;
++H[0];
poly::poly_inv(H, n, F);
poly::mul(G, F, n, n, F, n);
for (int ans, i = 1; i <= m; ++i) {
if (i == 2) {puts("-1"); continue;}
F[i] = (lint)F[i] * fac[i] % mod;
ans = (lint)fac[i - 1] * Pow(2, max(0ll, ((lint)i * (i - 1) / 2 - i)) % (mod - 1)) % mod * Pow(F[i], mod - 2) % mod;
printf("%d\n", ans);
}
return 0;
}