Submission #1080768

#TimeUsernameProblemLanguageResultExecution timeMemory
1080768andrei_iorgulescuAncient Books (IOI17_books)C++14
100 / 100
277 ms238796 KiB
#include <bits/stdc++.h> #include "books.h" #warning That's not FB, that's my FB using namespace std; using ll = long long; int inf = 1e9; int n, s; int p[1000005], pos[1000005]; vector<vector<int>> cyc; vector<int> cur; bool viz[1000005]; void dfs(int nod) { viz[nod] = true; cur.push_back(nod); if (!viz[p[nod]]) dfs(p[nod]); } int vmin[1000005], vmax[1000005]; int rmq_min[21][1000005], rmq_max[21][1000005]; int lg[1000005]; void build() { for (int i = 2; i <= n; i++) lg[i] = 1 + lg[i / 2]; for (int i = 1; i <= n; i++) { rmq_min[0][i] = vmin[i]; rmq_max[0][i] = vmax[i]; } for (int j = 1; j <= lg[n]; j++) { for (int i = 1; i <= n - (1 << j) + 1; i++) { rmq_min[j][i] = min(rmq_min[j - 1][i], rmq_min[j - 1][i + (1 << (j - 1))]); rmq_max[j][i] = max(rmq_max[j - 1][i], rmq_max[j - 1][i + (1 << (j - 1))]); } } } int qmin(int l, int r) { int lgg = lg[r - l + 1]; return min(rmq_min[lgg][l], rmq_min[lgg][r - (1 << lgg) + 1]); } int qmax(int l, int r) { int lgg = lg[r - l + 1]; return max(rmq_max[lgg][l], rmq_max[lgg][r - (1 << lgg) + 1]); } pair<int,int> query(int l, int r) { pair<int,int> uf = {qmin(l,r),qmax(l,r)}; return uf; } pair<int,int> f(pair<int,int> pos) { while (true) { pair<int,int> repos = query(pos.first,pos.second); if (repos.first == pos.first and repos.second == pos.second) break; pos = repos; } return pos; } int get_cl(pair<int,int> pos) { int cst = 0; int inip = pos.second; while (pos.second == inip and pos.first != 1) { cst++; pos.first--; pos = f(pos); } if (pos.second == inip) return inf; return cst; } int get_cr(pair<int,int> pos) { int cst = 0; int inip = pos.first; while (pos.first == inip and pos.second != n) { cst++; pos.second++; pos = f(pos); } if (pos.first == inip) return inf; return cst; } ll minimum_walk(vector<int> PERM, int STR) { cyc.clear(); memset(viz,0,sizeof(viz)); n = PERM.size(); for (int i = 1; i <= n; i++) p[i] = PERM[i - 1] + 1, pos[p[i]] = i; s = STR + 1; for (int i = 1; i <= n; i++) { if (!viz[i]) { cur.clear(); dfs(i); cyc.push_back(cur); } } for (auto it : cyc) { sort(it.begin(), it.end()); for (auto itt : it) vmin[itt] = it[0], vmax[itt] = it.back(); } build(); ll ans = 0; for (int i = 1; i <= n; i++) ans += abs(i - p[i]); int pzz = 1; while (pzz < s and p[pzz] == pzz) ans -= 2, pzz++; pzz = n; while (pzz > s and p[pzz] == pzz) ans -= 2, pzz--; pair<int,int> pos = f({s,s}); while (pos.first != 1 or pos.second != n) { int cl = get_cl(pos), cr = get_cr(pos); if (cl == inf) { while (pos.first != 1) { ans += 2; pos.first--; pos = f(pos); } while (pos.second != n) { ans += 2; pos.second++; pos = f(pos); } } else { if (cl <= cr) { for (int i = 1; i <= cl; i++) { ans += 2; pos.first--; pos = f(pos); } } else { for (int i = 1; i <= cr; i++) { ans += 2; pos.second++; pos = f(pos); } } } } return ans; } /** doamne cate try-uri pana sa ajung la greedy-ul corect daca faceam asta la cf era atat de over In fine, eu mereu domin un interval [L R] cu prop ca f(L, R) = (L, R) f(L, R) = (L, R) daca nu exista vreun i in (L R) care sa faca parte dintr-un ciclu care contine un j inn afara (L R) Altfel f(L, R) = f(intv reunit cu intervalul ciclului aluia kind of stuff), idk doar un aint de minime si maxime Acum, din (L, R) tu poti plati 2 bani ca sa faci artificial L-- sau R++ Fie cL = nr minim de mutari pe stanga astfel incat daca le faci, te extinzi pana la urma si in dreapta cR = nr minim de mutari in dreapta astfel incat pana la urma te extinzi in stanga Proof penal => e optim sa faci mutari in directia cu costul minim (adica faci min(cL, cR) mutari intr-o directie si vezi unde dai) Ma rog, daca cL = cR = inf (nu poate fi doar una inf si una nu, ofc), spamezi mutari in ambele parti pana ajungi la capat In fine, la final scazi 2 * (marimea sufixului de p[i] = i + marimea prefixului de p[i] = i) Kinda se reduce la a gasi cL si cR eficient... chestia funny e ca nu trebuie vreo structura complicata Gen, daca doar simulezi, oricum mereu te extinzi cu 1 intr-o parte, deci daca faci O(k) query-uri de aint, se va extinde (L, R) la final O(k) Deci tot O(NlogN) iese sau cv de genul Ce boti oamenii ca au bagat asa putini 50 -> 100 **/

Compilation message (stderr)

books.cpp:3:2: warning: #warning That's not FB, that's my FB [-Wcpp]
    3 | #warning That's not FB, that's my FB
      |  ^~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...