P14561 [CXOI2025] 我常常追忆过去
Fonder_Wish · · 题解
感觉这个 trick 见过后面就完全没有难度。类似的在 ARC163D。
对于竞赛图来说,SCC 个数与下面问题的答案是相同的:
集合
S 的个数,满足\varnothing \subset S \subseteq U = \{ 1, 2, \cdots, n \} ,且对于\forall u \in S, v \in U \setminus S ,存在u \to v 的边。
这是为什么,你考虑竞赛图缩点后仍然是竞赛图而且是 DAG,所以长成一个链状物,我们把这个东西重标号为
不妨算 SCC 总数然后除以
于是答案是
直接算复杂度是
一个因数只与
:::info[代码]
#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
using i64 = long long;
using i128 = __int128;
using u32 = unsigned int;
using u64 = unsigned long long;
using arr = array<int, 2>;
using vec = vector<int>;
using pii = pair<int, int>;
const int N = 1 << 22;
const int P = 998244353;
const int i2 = P + 1 >> 1;
int qPow(int x, int y) {
int res = 1;
for (; y; x = 1ll * x * x % P, y >>= 1)
if (y & 1) res = 1ll * res * x % P;
return res;
}
int add(int x, int y) { if ((x += y) >= P) x -= P; return x; }
int sub(int x, int y) { if ((x -= y) < 0) x += P; return x; }
namespace poly {
const int G(3), iG(332748118);
int tot, bit, r[N], itot, qp[N];
void Init(int l) {
qp[0] = tot = 1, bit = 0;
while (tot <= l) tot <<= 1, ++bit;
itot = qPow(tot, P - 2);
F(i, 1, tot - 1) r[i] = (r[i >> 1] >> 1) | ((i & 1) << bit - 1);
}
void NTT(int *f, bool tp) {
F(i, 1, tot - 1) if (i < r[i]) swap(f[i], f[r[i]]);
for (int d = 1; d < tot; d <<= 1) {
int w = qPow(tp ? iG : G, (P - 1) / (d << 1));
F(i, 1, d - 1) qp[i] = 1ll * qp[i - 1] * w % P;
for (int i = 0; i < tot; i += d << 1)
F(j, 0, d - 1) {
int x = f[i | j], y = 1ll * qp[j] * f[i | j | d] % P;
f[i | j] = add(x, y), f[i | j | d] = sub(x, y);
}
}
if (tp) F(i, 0, tot - 1) f[i] = 1ll * f[i] * itot % P;
}
}
int m, op, fc[N], iv[N];
int f[N], g[N], h[N];
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> m >> op, fc[0] = 1;
F(i, 1, m) fc[i] = 1ll * fc[i - 1] * i % P;
iv[m] = qPow(fc[m], P - 2);
dF(i, m, 1) iv[i - 1] = 1ll * iv[i] * i % P;
F(i, 1, m) f[i] = g[i] = 1ll * qPow(2, 1ll * i * (i - 1) / 2 % (P - 1)) * iv[i] % P;
g[0] = 1;
poly::Init(m << 1);
poly::NTT(f, 0), poly::NTT(g, 0);
F(i, 0, poly::tot - 1) h[i] = 1ll * f[i] * g[i] % P;
poly::NTT(h, 1);
F(i, 1, m) {
int z = qPow(i2, 1ll * i * (i - 1) / 2 % (P - 1));
h[i] = 1ll * fc[i] * h[i] % P * z % P;
}
if (op == 1) F(i, 1, m) cout << h[i] << "\n";
else {
int ans = 0;
F(i, 1, m) ans ^= h[i];
cout << ans << "\n";
}
return 0;
}
:::