ARC 082 E: ConvexScore
- Keywords
- convex hull DP
- Time Complexity
- \(O(N^3)\)
汎用的な処理が多数含まれているのでメモ。
#include <iostream> #include <algorithm> #include <vector> #include <complex> #include <cmath> #include <cassert> #include <tuple> using namespace std; constexpr long long mod = 998244353; using P = complex<long long>; long long dot(P a, P b) { return real(conj(a) * b); } long long cross(P a, P b) { return imag(conj(a) * b); } long long gcd(long long a, long long b) { a = abs(a); b = abs(b); if (b == 0) return a; return gcd(b, a % b); } // Get minimum element pointing in the same direction. P tomato(P a) { long long g = gcd(a.real(), a.imag()); return P(a.real() / g, a.imag() / g); } // Lexical order (argument, norm) bool argcomp(P p1, P p2) { bool a = p1.imag() > 0 || (p1.imag() == 0 && p1.real() >= 0); bool b = p2.imag() > 0 || (p2.imag() == 0 && p2.real() >= 0); if (a != b) return a; long long c = p2.real() * p1.imag(); long long d = p1.real() * p2.imag(); if (c != d) return c < d; return norm(p1) < norm(p2); } namespace std { bool operator<(const P &a, const P &b) { return argcomp(a, b); } } int main() { int n; cin >> n; vector<P> ps(n); for (int i = 0; i < n; i++) { int x, y; cin >> x >> y; ps[i] = P(x, y); } vector<pair<int, int>> es; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (i == j) continue; es.emplace_back(i, j); } } // If two vectors are pointing same direction, // these are arranged such that both aren't taken. sort(es.begin(), es.end(), [&](pair<int, int> a, pair<int, int> b) { P d = ps[a.second] - ps[a.first]; P e = ps[b.second] - ps[b.first]; if (cross(d, e) == 0 && dot(d, e) >= 0) { return dot(ps[a.second] - ps[a.first], ps[b.first] - ps[a.first]) < 0; } else { return d < e; } }); // Count the points inside (NOT on) the triangle(i,j,k) static int in[200][200][200]; for (int j = 0; j < n; j++) { vector<pair<P, int>> qs; for (int i = 0; i < n; i++) { if (i == j) continue; qs.emplace_back(ps[i] - ps[j], i); } sort(qs.begin(), qs.end()); for (int i = 0; i < n; i++) { if (i == j) continue; P s = tomato(ps[j] - ps[i]); int f = lower_bound(qs.begin(), qs.end(), make_pair(s, 0)) - qs.begin(); for (int l = 0; l < n - 1; l++) { int k = qs[(f + l) % (n - 1)].second; in[i][j][k] -= l + 1; in[j][k][i] -= l + 1; in[k][i][j] -= l + 1; } } } static int on[200][200]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (i == j) continue; for (int k = 0; k < n; k++) { if (i == k || j == k) continue; on[i][j] += cross(ps[k] - ps[i], ps[j] - ps[i]) == 0 && dot(ps[k] - ps[i], ps[j] - ps[i]) > 0 && dot(ps[k] - ps[j], ps[i] - ps[j]) > 0; in[i][j][k] = max(0, in[i][j][k] + n); } } } vector<long long> two(n + 1); two[0] = 1; for (int i = 1; i <= n; i++) { two[i] = two[i - 1] * 2 % mod; } // Easy long long ans = 0; for (int i = 0; i < n; i++) { vector<long long> dp1(n); vector<long long> dp2(n); for (auto e : es) { int u = e.first; int v = e.second; if (u == i) { assert(dp1[v] == 0); dp1[v] = two[on[u][v]]; } else if (v == i) { dp2[v] += dp2[u]; } else { int c = on[i][v] + on[u][v] + in[i][u][v]; dp2[v] += dp1[u] * two[c]; dp2[v] += dp2[u] * two[c]; } dp2[v] %= mod; } ans += dp2[i]; ans %= mod; } cout << ans << endl; }