C++の練習を兼ねて, AtCoder Beginner Contest 252 の 問題C (Slot Strategy) ~ 問題E (Road Reduction) を解いてみた.
■感想.
1. 問題Eは, 方針が見えなかったので, 解説を参考に, AC版に到達できたと思う.
2. 問題Eは, ダイクストラ法(応用版, 経路記録)の復習が出来たので, 非常に良かったと思う.
3. 引き続き, 時間を見つけて, 過去問の学習を進めていきたいと思う.
本家のサイト AtCoder Beginner Contest 252 解説 の 各リンク を ご覧下さい.
■C++版プログラム(問題C/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
|
// C++(GCC 9.2.1) #include <bits/stdc++.h> using namespace std; using vs = vector<string>; using vi = vector<int>; #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 pb push_back #define all(x) x.begin(), x.end() int t[101][10]; int main(){ // 1. 入力情報. int N; scanf("%d", &N); vs v; rep(i, N){ char c[22]; scanf("%s", c); string s(c); v.pb(s); } // 2. 各文字列の各数字が, 先頭に来る秒数は? rep(i, N) rep(j, 10) t[i][v[i][j] - '0'] = j; // 3. 各数字を揃えるために必要な時間から, 最小秒数を計算. int ans = 2020; rep(j, 10){ // N 回分保存. vi v; rep(i, N) v.pb(t[i][j]); // sort. sort(all(v)); // 必要秒数は? int bef = -1, c = 0, tCur = 0; for(auto &cur : v){ // 比較(指定された秒数に, 最大1回までしかボタンが押せない). c = (bef == cur) ? (c + 1) : 0; // 前回分更新. bef = cur; // 必要秒数更新. tCur = max(tCur, cur + 10 * c); } // 更新. ans = min(ans, tCur); } // 4. 出力. printf("%d\n", ans); 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 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
|
[入力例] 3 1937458062 8124690357 2385760149 [出力例] 6 ※AtCoderテストケースより [入力例] 5 0123456789 0123456789 0123456789 0123456789 0123456789 [出力例] 40 ※AtCoderテストケースより [入力例] 10 8321907546 0536427819 1457309682 8706139524 5289170463 4936027185 3481720596 2054783619 3976250481 7614398250 [出力例] 14 [入力例] 15 0254873961 9653248701 0193462758 6835104792 7058943261 2638104759 4081523679 8421075639 8042157369 0963187254 7623908541 3786590241 9201536748 7218543096 6584972103 [出力例] 23 [入力例] 20 1240369587 1490623857 7649508321 3158479026 0368712459 3501426987 5692407318 7063941852 8943571026 4208173695 4206973158 1795638204 1905843672 9806257314 3402817659 5943806127 0634597182 7205693481 5823940761 0461823579 [出力例] 27 |
■C++版プログラム(問題D/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
|
// C++(GCC 9.2.1) #include <bits/stdc++.h> using namespace std; 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 a first #define b second int a[202020]; int main(){ // 1. 入力情報. int N; scanf("%d", &N); map<int, int> mc, mi; rep(i, N){ scanf("%d", &a[i]); mi[a[i]] = 0; } // 2. 座標圧縮. int idx = -1; for(auto &p : mi) p.b = ++idx; // 3. 各整数の出現回数は? rep(i, N) ++mc[mi[a[i]]]; // 4. 集計. // 4-1. 1種類で構成される場合. LL ans = (LL)N * (LL)(N - 1) * (LL)(N - 2) / 6; for(auto &p : mc) ans -= (LL)p.b * (LL)(p.b - 1) * (LL)(p.b - 2) / 6; // 4-2. 2種類で構成される場合. for(auto &p : mc) ans -= (LL)p.b * (LL)(p.b - 1) / 2 * (LL)(N - p.b); // 5. 出力. printf("%lld\n", ans); 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
|
[入力例] 4 3 1 4 1 [出力例] 2 ※AtCoderテストケースより [入力例] 10 99999 99998 99997 99996 99995 99994 99993 99992 99991 99990 [出力例] 120 ※AtCoderテストケースより [入力例] 15 3 1 4 1 5 9 2 6 5 3 5 8 9 7 9 [出力例] 355 ※AtCoderテストケースより [入力例] 20 9 3 15 2 14 12 13 10 9 10 5 9 1 7 7 10 13 11 1 11 [出力例] 964 [入力例] 100 9 10 10 7 13 6 7 4 7 9 1 2 4 11 4 14 6 10 8 6 8 8 8 15 7 9 11 1 15 4 9 6 6 15 13 8 4 4 11 9 15 3 4 8 12 8 15 9 2 10 4 13 1 4 2 5 13 15 7 8 10 3 7 2 4 1 8 7 5 14 3 4 1 2 5 14 15 4 6 2 13 12 10 8 11 1 11 9 12 14 14 5 3 10 7 9 7 8 2 7 [出力例] 130654 [入力例] 500 20 17 10 4 20 8 20 4 2 12 7 9 3 16 11 20 10 19 16 3 16 3 17 14 16 15 8 4 1 12 14 19 8 9 15 1 2 5 5 14 7 5 8 5 13 17 11 13 7 17 3 3 3 10 18 15 2 12 17 18 7 5 6 6 9 15 12 7 11 6 1 3 2 5 1 10 13 12 8 1 4 4 11 16 5 9 3 19 18 14 13 9 19 19 17 16 18 15 3 5 16 9 10 7 18 3 6 3 11 4 17 4 1 3 9 4 18 5 7 12 18 17 12 2 12 20 13 1 19 13 9 5 14 11 2 13 7 9 16 4 12 9 7 14 17 9 20 12 3 12 14 15 11 18 1 2 4 2 1 5 18 2 6 20 9 11 19 5 8 15 5 12 8 10 9 8 12 13 17 6 9 10 7 3 18 10 14 14 5 3 10 8 7 18 5 12 2 10 3 1 12 14 19 18 11 11 11 11 13 1 19 17 14 3 7 6 12 7 4 11 14 18 12 2 8 4 6 9 17 16 9 9 7 11 20 4 12 4 11 11 14 7 20 9 16 9 18 4 3 8 12 1 12 16 11 2 10 8 3 18 5 8 18 18 10 13 15 14 1 3 6 6 17 10 9 5 5 2 5 8 14 9 6 5 9 8 4 5 10 4 4 9 15 7 8 4 9 11 1 9 8 19 18 15 17 10 8 4 9 3 15 1 11 11 8 8 9 13 9 5 12 12 2 19 16 1 18 14 3 6 20 4 8 3 3 11 16 18 13 9 9 18 11 18 16 15 7 9 9 16 8 2 11 4 18 16 19 6 6 10 13 3 7 11 11 19 8 11 14 19 16 13 5 16 14 9 6 19 19 14 13 19 17 3 3 1 7 10 7 19 15 14 5 13 12 7 15 16 14 18 1 6 19 11 10 7 6 17 5 1 5 7 20 10 8 2 2 10 3 1 10 13 12 2 16 18 6 7 17 6 6 14 10 14 13 15 14 15 5 15 5 20 17 6 1 8 13 19 17 13 13 2 3 18 7 2 19 20 5 9 7 15 19 19 12 1 5 19 6 6 10 13 10 9 12 1 15 13 13 13 17 5 10 13 12 19 8 19 1 2 3 13 10 16 10 14 19 15 11 12 [出力例] 17714610 |
■C++版プログラム(問題E/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
|
// 解き直し. // https://atcoder.jp/contests/abc252/editorial/3980 // C++(GCC 9.2.1) #include <bits/stdc++.h> using namespace std; using LL = long long; using vi = vector<int>; using P = pair<int, int>; #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 pb push_back const LL INF = 202020202020202020; int route[202020]; struct edge{ int n; // 次の頂点. LL c; // コスト. bool operator < (const edge &E) const{ return c > E.c; } }; vector<edge> G[202020]; int main(){ // 1. 入力情報. int N, M; scanf("%d %d", &N, &M); map<P, int> me; rep(i, M){ int a, b; LL c; scanf("%d %d %lld", &a, &b, &c); --a; --b; G[a].pb(edge{b, c}); G[b].pb(edge{a, c}); // 辺情報. me[{a, b}] = me[{b, a}] = i + 1; } // 2. ダイクストラ法. // https://ja.wikipedia.org/wiki/ダイクストラ法 auto dijkstra = [&](int s, LL* d, int* memo){ // 初期化. priority_queue<edge> pq; // 始点設定. d[s] = 0; pq.push({s, 0LL}); // キュー pq が 空になるまで, 探索. while(!pq.empty()){ // 探索を継続するために, 頂点を取得. edge e = pq.top(); pq.pop(); int cn = e.n; LL cc = e.c; // 訪問済みフラグ設定. if(memo[cn]) continue; memo[cn]++; // 各隣接する頂点について, 距離を確認し, 移動コストを更新. for(auto &g : G[cn]){ // 移動コスト更新. int nn = g.n; LL nc = cc + g.c; if(d[nn] > nc){ d[nn] = nc; pq.push({nn, nc}); // 各都市に到達する直前の道路を記録(最大, 1個まで). route[nn] = cn; } } } }; // 3. 各都市までの, 最小コスト. LL d[N]; int memo[N]; rep(i, N) d[i] = INF, memo[i] = 0; dijkstra(0, d, memo); // 4. 辺情報に変換. vi ans; repx(i, 1, N) ans.pb(me[{i, route[i]}]); // 5. 出力. rep(i, N - 1) printf("%d%s", ans[i], (i < N - 2) ? " " : "\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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
|
[入力例] 3 3 1 2 1 2 3 2 1 3 10 [出力例] 1 2 ※AtCoderテストケースより [入力例] 4 6 1 2 1 1 3 1 1 4 1 2 3 1 2 4 1 3 4 1 [出力例] 3 1 2 ※AtCoderテストケースより ※但し, 上記のプログラムでは, 以下の内容が出力される. 1 2 3 [入力例] 10 12 2 3 1 2 6 1 1 3 1 3 6 1 6 7 3 8 10 1 7 10 1 5 8 6 5 9 3 8 9 1 4 5 1 1 4 1 [出力例] 1 3 12 11 4 5 10 9 7 [入力例] 15 19 1 2 3 2 10 1 2 9 4 8 9 5 8 11 1 9 11 2 5 9 1 5 6 3 1 6 1 1 12 2 12 15 7 12 13 1 13 15 2 4 6 1 4 7 3 3 7 1 3 4 5 4 14 6 5 14 8 [出力例] 1 16 14 8 9 15 5 7 2 6 10 12 18 13 |
■参照サイト
AtCoder Beginner Contest 252