Submission #601896

#TimeUsernameProblemLanguageResultExecution timeMemory
601896model_codeGiraffes (JOI22_giraffes)C++17
100 / 100
2868 ms2052 KiB
/* 100-POINT SOLUTION FOR "GIRAFFES" (JOI 2022 OPEN CONTEST) - Solution: Speeding up dynamic programming with sweepline algorithm using segment tree - Time Complexty: O(N log N * (N - answer)) (= O(N^1.5 log N) for average case) */ #include <vector> #include <iostream> #include <algorithm> using namespace std; class segtree { private: int sz; std::vector<int> val; public: static const int INF = 2012345678; segtree() : sz(0), val(std::vector<int>()) {}; segtree(int n) { sz = 1; while (sz < n) { sz *= 2; } val = std::vector<int>(sz * 2, INF); } void reset() { for (int i = 0; i < sz * 2; i++) { val[i] = INF; } } void upgrade(int pos, int x) { pos += sz; val[pos] = std::min(val[pos], x); while (pos > 1) { pos >>= 1; val[pos] = std::min(val[pos * 2], val[pos * 2 + 1]); } } int rangemin(int l, int r) { l += sz; r += sz; int answer = INF; while (l != r) { if ((l & 1) == 1) answer = std::min(answer, val[l++]); if ((r & 1) == 1) answer = std::min(answer, val[--r]); l >>= 1; r >>= 1; } return answer; } }; class square { public: int x, y, l; square() : x(0), y(0), l(0) {}; square(int x_, int y_, int l_) : x(x_), y(y_), l(l_) {}; }; int solve(int N, const vector<int>& P) { // dp[i][j]: smallest size of square of "answer = t" with point (j, P[j]) at direction i const int INF = 1012345678; vector<vector<int> > dp(4, vector<int>(N, 0)); int t = 1; // step #0. preparation vector<int> pa(N), pb(N); for (int i = 0; i < N; i++) { pa[i] = i; pb[i] = i; } sort(pa.begin(), pa.end(), [&](int i, int j) { return i - P[i] < j - P[j]; }); sort(pb.begin(), pb.end(), [&](int i, int j) { return i + P[i] < j + P[j]; }); while (true) { // step #1. enumerate all squares vector<square> sq; for (int i = 0; i < 4; i++) { for (int j = 0; j < N; j++) { if (dp[i][j] != INF) { int x = j - (i & 2 ? dp[i][j] : 0); int y = P[j] - (i & 1 ? dp[i][j] : 0); sq.push_back(square(x, y, dp[i][j])); } } } int S = sq.size(); // step #2. preparation dp = vector<vector<int> >(4, vector<int>(N, INF)); vector<square> sqa = sq; sort(sqa.begin(), sqa.end(), [](const square& s1, const square& s2) { return s1.x - s1.y < s2.x - s2.y; }); vector<square> sqb = sq; sort(sqb.begin(), sqb.end(), [](const square& s1, const square& s2) { return s1.x + s1.y + s1.l < s2.x + s2.y + s2.l; }); segtree seg1(N); segtree seg2(N); int posp, possq; // step #3. sweepline by increasing x-y seg1.reset(); seg2.reset(); posp = 0; possq = 0; while (posp != N || possq != S) { int px = pa[posp]; int py = P[pa[posp]]; int v1 = (posp != N ? px - py : INF); int v2 = (possq != S ? sqa[possq].x - sqa[possq].y : INF); if (v1 >= v2) { seg1.upgrade(sqa[possq].x, sqa[possq].y + sqa[possq].l); seg2.upgrade(sqa[possq].y + sqa[possq].l, -sqa[possq].x); possq += 1; } else { dp[0][px] = min(dp[0][px], seg1.rangemin(px + 1, N) - py); dp[3][px] = min(dp[3][px], px - (-seg2.rangemin(0, py))); posp += 1; } } // step #4. sweepline by decreasing x-y seg1.reset(); seg2.reset(); posp = N - 1; possq = S - 1; while (posp != -1 || possq != -1) { int px = pa[posp]; int py = P[pa[posp]]; int v1 = (posp != -1 ? px - py : -INF); int v2 = (possq != -1 ? sqa[possq].x - sqa[possq].y : -INF); if (v1 <= v2) { seg1.upgrade(sqa[possq].y, sqa[possq].x + sqa[possq].l); seg2.upgrade(sqa[possq].x + sqa[possq].l, -sqa[possq].y); possq -= 1; } else { dp[0][px] = min(dp[0][px], seg1.rangemin(py + 1, N) - px); dp[3][px] = min(dp[3][px], py - (-seg2.rangemin(0, px))); posp -= 1; } } // step #5. sweepline by increasing x+y seg1.reset(); seg2.reset(); posp = 0; possq = 0; while (posp != N || possq != S) { int px = pb[posp]; int py = P[pb[posp]]; int v1 = (posp != N ? px + py : INF); int v2 = (possq != S ? sqb[possq].x + sqb[possq].y + sqb[possq].l : INF); if (v1 >= v2) { seg1.upgrade(sqb[possq].x, -sqb[possq].y); seg2.upgrade(sqb[possq].y, -sqb[possq].x); possq += 1; } else { dp[1][px] = min(dp[1][px], py - (-seg1.rangemin(px + 1, N))); dp[2][px] = min(dp[2][px], px - (-seg2.rangemin(py + 1, N))); posp += 1; } } // step #6. sweepline by decreasing x+y seg1.reset(); seg2.reset(); posp = N - 1; possq = S - 1; while (posp != -1 || possq != -1) { int px = pb[posp]; int py = P[pb[posp]]; int v1 = (posp != -1 ? px + py : -INF); int v2 = (possq != -1 ? sqb[possq].x + sqb[possq].y + sqb[possq].l : -INF); if (v1 <= v2) { seg1.upgrade(sqb[possq].y + sqb[possq].l, sqb[possq].x + sqb[possq].l); seg2.upgrade(sqb[possq].x + sqb[possq].l, sqb[possq].y + sqb[possq].l); possq -= 1; } else { dp[1][px] = min(dp[1][px], seg1.rangemin(0, py) - px); dp[2][px] = min(dp[2][px], seg2.rangemin(0, px) - py); posp -= 1; } } // step #7. final cleanup for (int i = 0; i < 4; i++) { for (int j = 0; j < N; j++) { int xlim = (i & 2 ? j : (N - 1) - j); int ylim = (i & 1 ? P[j] : (N - 1) - P[j]); if (dp[i][j] > min(xlim, ylim)) { dp[i][j] = INF; } } } if (dp == vector<vector<int> >(4, vector<int>(N, INF))) { break; } t += 1; } return N - t; } int main() { int N; cin >> N; vector<int> P(N); for (int i = 0; i < N; i++) { cin >> P[i]; P[i] -= 1; } int answer = solve(N, P); cout << answer << endl; return 0; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...