The 2025 ICPC Asia Nanjing Regional Contest - M. Many Convex Polygons

哎哎,死在这题了,没想到求面积用外积,想到外积这道题就没什么难度了。
枚举一个 \(k\) 边形,其面积可以由逆时针排序的 \(k\) 点确定为:
\[S = \sum_{i = 0}^{k - 1}(x_iy_{(i + 1) \bmod k} - x_{(i + 1) \bmod k}y_i)
\]
本质其实是若干个原点三角形的面积和,我们可以考虑钦定三角形来计算出所有多边形中这个三角形的贡献。
考虑一条弦 \((x_i, \, y_i), \, (x_{(i + d) \bmod k}, \, y_{(i + d) \bmod k})\),将多边形分为两部分,其中一部分含 \(d - 1\) 个点,另一部分含 \(n - d - 1\) 个点,我们可以在其中一部分再选择 \(k - 2\) 个点构成 \(k\) 边形,此时原点三角形的面积为 \(x_iy_{(i + d) \bmod k} - x_{(i + d) \bmod k}y_i\),显然该三角形的贡献唯一确定为:
\[S_i = \binom{n - d - 1}{k - 2}(x_iy_{(i + d) \bmod n} - x_{(i + d) \bmod n}y_i)
\]
故差距为 \(d\) 的弦所对应的三角形的面积和:
\[f_d = \sum_{i = 0}^{n - 1}(x_iy_{(i + d) \bmod n} - x_{(i + d) \bmod n}y_i)
\]
做一次循环差卷积就可以得到所有 \(f\),而差距为 \(d\) 的弦所对应三角形的出现次数均相等,所以枚举 \(k\) 边形时所对应系数均相同,也就是说答案应当为:
\[Ans_k = \sum_{i = 1}^{n - 1}\binom{n - i - 1}{k - 2}f_i = \frac{1}{(k - 2)!}\sum_{i = 1}^{n - k + 1}\frac{(n - i - 1)!f_i}{(n - i - k + 1)!}
\]
对每一个 \(k\) 的答案可以做一个差卷积得到:
设 \(F(x) = \sum\limits_{i = 0}^{n - 1}(n - i - 1)!f_i\),\(G(x) = \sum\limits_{i = 0}^{n + 1}\dfrac{1}{(n - i + 1)!}\),\(F\) 取反后卷积后第 \(n + k - 1\) 项就是所求 \(k\) 的答案。
参考代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define i128 __int128
#define ull unsigned long long
#define clr(f, n) memset(f, 0, sizeof(int) * (n))
#define cpy(f, g, n) memcpy(f, g, sizeof(int) * (n))
#define rev(f, n) reverse(f, f + (n))
const int _G = 3, _i = 86583718, mod = 998244353, INF = 1e9;
const int N = 6e5 + 10;
ll qpow(ll a, ll k = mod - 2) {
ll res = 1;
while (k) {
if (k & 1) res = res * a % mod;
k >>= 1;
a = a * a % mod;
}
return res;
}
const int invG = qpow(_G), invi = qpow(_i), inv2 = qpow(2);
int rev[N << 1], rev_len;
void rev_init(int n) {
if (rev_len == n) return;
for (int i = 0; i < n; i ++ ) rev[i] = (rev[i >> 1] >> 1) | (i & 1 ? n >> 1 : 0);
rev_len = n;
}
void NTT(int *g, int op, int n) {
rev_init(n);
static ull f[N << 1], Gk[N << 1] = {1};
for (int i = 0; i < n; i ++ ) f[i] = g[rev[i]];
for (int k = 1; k < n; k <<= 1) {
int G1 = qpow(~op ? _G : invG, (mod - 1) / (k << 1));
for (int i = 1; i < k; i ++ ) Gk[i] = Gk[i - 1] * G1 % mod;
for (int i = 0; i < n; i += k << 1) {
for (int j = 0; j < k; j ++ ) {
int tmp = Gk[j] * f[i | j | k] % mod;
f[i | j | k] = f[i | j] + mod - tmp;
f[i | j] += tmp;
}
}
if (k == (1 << 10)) for (int i = 0; i < n; i ++ ) f[i] %= mod;
}
if (~op) for (int i = 0; i < n; i ++ ) g[i] = f[i] % mod;
else {
int invn = qpow(n);
for (int i = 0; i < n; i ++ ) g[i] = f[i] % mod * invn % mod;
}
}
void px(int *f, int *g, int n) {
for (int i = 0; i < n; i ++ ) f[i] = 1ll * f[i] * g[i] % mod;
}
int inv[N << 1], inv_len;
void inv_init(int n) {
if (n <= inv_len) return;
if (!inv_len) inv[0] = inv[1] = 1, inv_len = 1;
for (int i = inv_len + 1; i <= n; i ++ ) inv[i] = 1ll * inv[mod % i] * (mod - mod / i) % mod;
inv_len = n;
}
void covolution(int *f, int *g, int len, int lim) {
static int sav[N << 1];
int n; for (n = 1; n < len << 1; n <<= 1);
clr(sav, n); cpy(sav, g, n);
NTT(sav, 1, n); NTT(f, 1, n);
px(f, sav, n); NTT(f, -1, n);
clr(f + lim, n - lim), clr(sav, n);
}
void cycle_covolution(int *f, int *g, int len) {
static int sav[N << 1];
int n; for (n = 1; n < len << 1; n <<= 1);
clr(sav, n); cpy(sav, g, n);
NTT(sav, 1, n); NTT(f, 1, n);
px(f, sav, n); NTT(f, -1, n);
for (int i = len; i < n; i ++ ) f[i - len] = (f[i - len] + f[i]) % mod;
clr(f + len, n - len), clr(sav, n);
}
int n, x[N], y[N];
int F[N << 1], G[N << 1];
ll frac[N], inv_frac[N], f[N], ans[N];
void solve() {
cin >> n;
for (int i = 0; i < n; i ++ ) cin >> x[i] >> y[i];
for (int i = 0; i < n; i ++ ) x[i] = (x[i] % mod + mod) % mod, y[i] = (y[i] % mod + mod) % mod;
frac[0] = inv_frac[0] = 1;
for (int i = 1; i <= n + 1; i ++ ) frac[i] = frac[i - 1] * i % mod;
inv_frac[n + 1] = qpow(frac[n + 1]);
for (int i = n; i >= 1; i -- ) inv_frac[i] = inv_frac[i + 1] * (i + 1) % mod;
for (int i = 0; i < n; i ++ ) F[i] = x[i], G[i] = y[i];
reverse(F, F + n); cycle_covolution(F, G, n);
for (int i = 0; i < n; i ++ ) f[(i + 1) % n] = F[i];
for (int i = 0; i < n; i ++ ) F[i] = x[i], G[i] = y[i];
reverse(G, G + n); cycle_covolution(G, F, n);
for (int i = 0; i < n; i ++ ) (f[(i + 1) % n] += mod - G[i]) %= mod;
for (int i = 0; i < n; i ++ ) F[i] = frac[n - i - 1] * f[i] % mod;
for (int i = 0; i <= n + 1; i ++ ) G[i] = inv_frac[n - i + 1];
reverse(F, F + n); covolution(F, G, n << 1, n << 1);
for (int i = 3; i <= n; i ++ ) ans[i] = F[n + i - 1] * inv_frac[i - 2] % mod;
for (int i = 3; i <= n; i ++ ) cout << ans[i] << "\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
// cin >> T;
while (T -- ) solve();
return 0;
}

浙公网安备 33010602011771号