/*
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;
}
# |
결과 |
실행 시간 |
메모리 |
Grader output |
1 |
Correct |
1 ms |
212 KB |
Output is correct |
2 |
Correct |
1 ms |
212 KB |
Output is correct |
3 |
Correct |
0 ms |
212 KB |
Output is correct |
4 |
Correct |
0 ms |
212 KB |
Output is correct |
5 |
Correct |
0 ms |
212 KB |
Output is correct |
6 |
Correct |
1 ms |
212 KB |
Output is correct |
7 |
Correct |
2 ms |
292 KB |
Output is correct |
8 |
Correct |
1 ms |
212 KB |
Output is correct |
9 |
Correct |
1 ms |
300 KB |
Output is correct |
10 |
Correct |
1 ms |
212 KB |
Output is correct |
# |
결과 |
실행 시간 |
메모리 |
Grader output |
1 |
Correct |
1 ms |
212 KB |
Output is correct |
2 |
Correct |
1 ms |
212 KB |
Output is correct |
3 |
Correct |
0 ms |
212 KB |
Output is correct |
4 |
Correct |
0 ms |
212 KB |
Output is correct |
5 |
Correct |
0 ms |
212 KB |
Output is correct |
6 |
Correct |
1 ms |
212 KB |
Output is correct |
7 |
Correct |
2 ms |
292 KB |
Output is correct |
8 |
Correct |
1 ms |
212 KB |
Output is correct |
9 |
Correct |
1 ms |
300 KB |
Output is correct |
10 |
Correct |
1 ms |
212 KB |
Output is correct |
11 |
Correct |
1 ms |
212 KB |
Output is correct |
12 |
Correct |
0 ms |
212 KB |
Output is correct |
13 |
Correct |
1 ms |
212 KB |
Output is correct |
14 |
Correct |
1 ms |
212 KB |
Output is correct |
15 |
Correct |
1 ms |
212 KB |
Output is correct |
16 |
Correct |
1 ms |
216 KB |
Output is correct |
17 |
Correct |
1 ms |
300 KB |
Output is correct |
18 |
Correct |
1 ms |
212 KB |
Output is correct |
19 |
Correct |
1 ms |
300 KB |
Output is correct |
20 |
Correct |
1 ms |
212 KB |
Output is correct |
# |
결과 |
실행 시간 |
메모리 |
Grader output |
1 |
Correct |
1 ms |
212 KB |
Output is correct |
2 |
Correct |
1 ms |
212 KB |
Output is correct |
3 |
Correct |
0 ms |
212 KB |
Output is correct |
4 |
Correct |
0 ms |
212 KB |
Output is correct |
5 |
Correct |
0 ms |
212 KB |
Output is correct |
6 |
Correct |
1 ms |
212 KB |
Output is correct |
7 |
Correct |
2 ms |
292 KB |
Output is correct |
8 |
Correct |
1 ms |
212 KB |
Output is correct |
9 |
Correct |
1 ms |
300 KB |
Output is correct |
10 |
Correct |
1 ms |
212 KB |
Output is correct |
11 |
Correct |
1 ms |
212 KB |
Output is correct |
12 |
Correct |
0 ms |
212 KB |
Output is correct |
13 |
Correct |
1 ms |
212 KB |
Output is correct |
14 |
Correct |
1 ms |
212 KB |
Output is correct |
15 |
Correct |
1 ms |
212 KB |
Output is correct |
16 |
Correct |
1 ms |
216 KB |
Output is correct |
17 |
Correct |
1 ms |
300 KB |
Output is correct |
18 |
Correct |
1 ms |
212 KB |
Output is correct |
19 |
Correct |
1 ms |
300 KB |
Output is correct |
20 |
Correct |
1 ms |
212 KB |
Output is correct |
21 |
Correct |
1 ms |
212 KB |
Output is correct |
22 |
Correct |
2 ms |
212 KB |
Output is correct |
23 |
Correct |
6 ms |
348 KB |
Output is correct |
24 |
Correct |
7 ms |
340 KB |
Output is correct |
25 |
Correct |
10 ms |
340 KB |
Output is correct |
26 |
Correct |
10 ms |
376 KB |
Output is correct |
27 |
Correct |
11 ms |
296 KB |
Output is correct |
28 |
Correct |
12 ms |
296 KB |
Output is correct |
29 |
Correct |
11 ms |
340 KB |
Output is correct |
30 |
Correct |
11 ms |
340 KB |
Output is correct |
# |
결과 |
실행 시간 |
메모리 |
Grader output |
1 |
Correct |
1 ms |
212 KB |
Output is correct |
2 |
Correct |
1 ms |
212 KB |
Output is correct |
3 |
Correct |
0 ms |
212 KB |
Output is correct |
4 |
Correct |
0 ms |
212 KB |
Output is correct |
5 |
Correct |
0 ms |
212 KB |
Output is correct |
6 |
Correct |
1 ms |
212 KB |
Output is correct |
7 |
Correct |
2 ms |
292 KB |
Output is correct |
8 |
Correct |
1 ms |
212 KB |
Output is correct |
9 |
Correct |
1 ms |
300 KB |
Output is correct |
10 |
Correct |
1 ms |
212 KB |
Output is correct |
11 |
Correct |
1 ms |
212 KB |
Output is correct |
12 |
Correct |
0 ms |
212 KB |
Output is correct |
13 |
Correct |
1 ms |
212 KB |
Output is correct |
14 |
Correct |
1 ms |
212 KB |
Output is correct |
15 |
Correct |
1 ms |
212 KB |
Output is correct |
16 |
Correct |
1 ms |
216 KB |
Output is correct |
17 |
Correct |
1 ms |
300 KB |
Output is correct |
18 |
Correct |
1 ms |
212 KB |
Output is correct |
19 |
Correct |
1 ms |
300 KB |
Output is correct |
20 |
Correct |
1 ms |
212 KB |
Output is correct |
21 |
Correct |
1 ms |
212 KB |
Output is correct |
22 |
Correct |
2 ms |
212 KB |
Output is correct |
23 |
Correct |
6 ms |
348 KB |
Output is correct |
24 |
Correct |
7 ms |
340 KB |
Output is correct |
25 |
Correct |
10 ms |
340 KB |
Output is correct |
26 |
Correct |
10 ms |
376 KB |
Output is correct |
27 |
Correct |
11 ms |
296 KB |
Output is correct |
28 |
Correct |
12 ms |
296 KB |
Output is correct |
29 |
Correct |
11 ms |
340 KB |
Output is correct |
30 |
Correct |
11 ms |
340 KB |
Output is correct |
31 |
Correct |
383 ms |
788 KB |
Output is correct |
32 |
Correct |
1471 ms |
1500 KB |
Output is correct |
33 |
Correct |
2451 ms |
2008 KB |
Output is correct |
34 |
Correct |
2363 ms |
1992 KB |
Output is correct |
35 |
Correct |
2360 ms |
1948 KB |
Output is correct |
36 |
Correct |
2570 ms |
1956 KB |
Output is correct |
37 |
Correct |
2348 ms |
2052 KB |
Output is correct |
38 |
Correct |
2423 ms |
2024 KB |
Output is correct |
39 |
Correct |
2868 ms |
1988 KB |
Output is correct |
40 |
Correct |
2631 ms |
2020 KB |
Output is correct |