1+ /*
2+ IOI 2017 Ancient Books
3+ - The base cost will be sum(|P[i] - i|) for each i
4+ - Case S = 0:
5+ - Consider the cycles formed from the permutation
6+ - If two cycles "overlap", then Aryan can sort them simultaneously at no extra cost
7+ - We can thus "merge" overlapping cycles and discard any books that Aryan won't walk past
8+ - The extra cost will be 2 * (No. of unmerged cycles - 1)
9+ - We can extend this idea to work with S != 0
10+ - Let extend(l, r) = Given l and r, find the bounds of the merged cycle containing [l, r]
11+ - We can compute extend(l, r) in amortized linear time
12+ - Let dp[l, r] = Minimum extra cost Aryan needs given that all books in [l, r] are sorted
13+ = 0 if [l, r] == The entire range of books Aryan needs to sort
14+ 2 + min(dp[extend(l - 1, r)], dp[extend(l, r + 1)]) otherwise
15+ - We can reduce the number of states we visit by noticing that if extend(l - 1, r)^x contains
16+ extend(l, r + 1) and extend(l, r + 1)^y contains extend(l - 1, r), then we know that
17+ extend(l - 1, r)^x == extend(l, r + 1)^y
18+ - This means that the extra cost is simply 2 * min(x, y), and we can find each min(x, y) for
19+ each [l, r] in amortized linear time
20+ - Complexity: O(N)
21+ */
22+
23+ #include " books.h"
24+
25+ #include < bits/stdc++.h>
26+ typedef long long ll;
27+ using namespace std ;
28+
29+ int crit_l, crit_r;
30+ int cmp[1000000 ], cmp_l[1000000 ], cmp_r[1000000 ];
31+
32+ void extend (int &l, int &r) {
33+ int ext_l = min (cmp_l[cmp[l]], cmp_l[cmp[r]]);
34+ int ext_r = max (cmp_r[cmp[l]], cmp_r[cmp[r]]);
35+ while (l != ext_l || r != ext_r) {
36+ if (l != ext_l) {
37+ l--;
38+ ext_l = min (ext_l, cmp_l[cmp[l]]);
39+ ext_r = max (ext_r, cmp_r[cmp[l]]);
40+ } else {
41+ r++;
42+ ext_l = min (ext_l, cmp_l[cmp[r]]);
43+ ext_r = max (ext_r, cmp_r[cmp[r]]);
44+ }
45+ }
46+ }
47+
48+ ll compute (int l, int r) {
49+ extend (l, r);
50+ if (l == crit_l && r == crit_r) return 0 ;
51+ if (l == crit_l) return compute (l, r + 1 ) + 2 ;
52+ if (r == crit_r) return compute (l - 1 , r) + 2 ;
53+
54+ ll to_l = 2 ;
55+ int nl = l - 1 , nr = r, tl = l, tr = r + 1 ;
56+ extend (nl, nr), extend (tl, tr);
57+ while (nl != crit_l && nr < tr) {
58+ to_l += 2 ;
59+ nl--;
60+ extend (nl, nr);
61+ }
62+ if (nr < tr) return to_l + compute (nl, nr);
63+
64+ ll to_r = 2 ;
65+ nl = l, nr = r + 1 , tl = l - 1 , tr = r;
66+ extend (nl, nr), extend (tl, tr);
67+ while (nl > tl) {
68+ to_r += 2 ;
69+ nr++;
70+ extend (nl, nr);
71+ }
72+ return min (to_l, to_r) + compute (nl, nr);
73+ }
74+
75+ ll minimum_walk (vector<int > p, int s) {
76+ int n = p.size (), cmp_cnt = 0 ;
77+ fill (cmp, cmp + n, -1 );
78+ crit_l = s, crit_r = s;
79+ ll intra = 0 ;
80+ for (int i = 0 ; i < n; i++) {
81+ intra += abs (p[i] - i);
82+ if (cmp[i] == -1 ) {
83+ int curr = i;
84+ cmp_l[cmp_cnt] = cmp_r[cmp_cnt] = i;
85+ do {
86+ cmp[curr] = cmp_cnt;
87+ cmp_r[cmp_cnt] = max (cmp_r[cmp_cnt], curr);
88+ curr = p[curr];
89+ } while (curr != i);
90+ if (i != p[i]) {
91+ crit_l = min (crit_l, cmp_l[cmp_cnt]);
92+ crit_r = max (crit_r, cmp_r[cmp_cnt]);
93+ }
94+ cmp_cnt++;
95+ }
96+ }
97+ return intra + compute (s, s);
98+ }
0 commit comments