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