C++の練習を兼ねて, AtCoder Grand Contest 036 の 問題B (Do Not Duplicate) を解いてみた.
■感想.
1. 問題Bは, 解答方針が見えなかったので, 解説を参考に実装して, ようやく, AC版に到達できた.
2. 実装に苦労したものの, ダブリングを復習することが出来たので, 非常に良かったと思う..
3. 時間を見つけて, 引き続き, 過去問を振り返っていきたいと思う.
本家のサイト AtCoder Grand Contest 036 解説 を ご覧下さい.
■C++版プログラム(問題B/AC版).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
// 解き直し. // https://img.atcoder.jp/agc036/editorial.pdf // C++(GCC 9.2.1) #include <bits/stdc++.h> using namespace std; using vi = vector<int>; using vvi = vector<vi>; using LL = long long; #define repex(i, a, b, c) for(int i = a; i < b; i += c) #define repx(i, a, b) repex(i, a, b, 1) #define rep(i, n) repx(i, 0, n) #define repr(i, a, b) for(int i = a; i >= b; i--) #define pob pop_back #define pub push_back #define all(x) x.begin(), x.end() int a[202020], y[202020], stock[202020]; LL g[59][202020]; int main(){ // 1. 入力情報. int N; LL K; scanf("%d %lld", &N, &K); vvi v(202020); rep(i, N){ scanf("%d", &a[i]); v[a[i]].pub(i); } // 2. y[a] を 計算. rep(i, N){ int l = v[a[i]].size(); if(l == 1) y[i] = i + N + 1; if(l != 1){ int at = lower_bound(all(v[a[i]]), i) - v[a[i]].begin(); if(at < l - 1) y[i] = v[a[i]][at + 1] + 1; else y[i] = v[a[i]][0] + N + 1; } } // 3. Doubling. rep(i, N) g[0][i] = y[i]; int u = 0; LL bef = 0, cur = 0, r = 0, maxG = 0; repx(i, 1, 59){ rep(j, N){ // 前回分取得. bef = g[i - 1][j]; r = bef % N; // 今回分設定. cur = (bef - r) + g[i - 1][r]; g[i][j] = cur; // 最大値更新. maxG = max(maxG, cur); } // 最大値が大きい場合は, 終了. // -> オーバーフロー防止のため. if(maxG > 1e18){ u = i; break; } } // 4. Step 1 が 終了するタイミング の aStop は? LL aStop = 0, upper = N * K - 1; int idx = 0; while(upper - aStop > (LL)N){ // 探索. LL t = 0; rep(i, u + 1){ if(g[i][idx] - idx <= upper - aStop) t = g[i][idx]; else break; } // 更新. aStop += (t - idx); idx = t % N; } // 5. aStop, aStop + 1, ... , N * K - 1 について操作. int aStart = (int)(aStop % N); deque<int> ans; repx(i, aStart, N){ if(stock[a[i]]){ bool ok = true; while(ok){ // 該当要素が見つかったら, フラグ更新. int t = ans.back(); if(t == a[i]) ok = false; stock[t]--; ans.pob(); } }else{ stock[a[i]]++; ans.pub(a[i]); } } // 6. 出力. int l = ans.size(); rep(i, l){ printf("%d", ans[i]); printf("%s", (i < l - 1) ? " " : "\n"); } return 0; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
[入力例] 3 2 1 2 3 [出力例] 2 3 ※AtCoderのテストケースより [入力例] 5 10 1 2 3 2 3 [出力例] 3 ※AtCoderのテストケースより [入力例] 6 1000000000000 1 1 2 2 3 3 [出力例] ※AtCoderのテストケースより [入力例] 11 97 3 1 4 1 5 9 2 6 5 3 5 [出力例] 9 2 6 ※AtCoderのテストケースより [入力例] 7 11 7 1 2 7 3 4 5 [出力例] 5 [入力例] 15 7 15 2 1 7 1 2 1 5 3 8 2 12 10 13 5 [出力例] 7 [入力例] 50 2021 13 18 53 45 22 3 13 45 18 4 54 22 20 55 39 19 14 29 8 9 47 15 39 46 9 31 24 31 27 25 16 42 31 44 24 31 45 53 2 45 53 53 47 25 10 2 3 18 11 21 [出力例] 53 47 25 10 2 3 18 11 21 |
■参照サイト
AtCoder Grand Contest 036