C++の練習を兼ねて, AtCoder Regular Contest 118 の 問題D (Hamiltonian Cycle) を解いてみた.
■感想.
1. 問題D は, 方針が見えなかったので, 解説を参考にして, ようやく, AC版に到達出来た.
2. 個人的には, ハミルトン閉路 の 性質に 触れることが出来たので, 非常に, 良かったと思う.
3. 引き続き, 時間を見つけて, 過去問の学習を進めていきたいと思う.
本家のサイト AtCoder Regular Contest 118 解説 の 各リンク を ご覧下さい.
■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 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 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
// 解き直し. // https://atcoder.jp/contests/arc118/editorial/1210 // C++(GCC 9.2.1) #include <bits/stdc++.h> using namespace std; using LL = long long; using vl = vector<LL>; using vvl = vector<vl>; #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 int main(){ // 1. 入力情報. int P; LL a, b; scanf("%d %lld %lld", &P, &a, &b); // 2. a の 冪乗 が 1 となる n. int n = -1; LL cur = 1; set<LL> H; H.insert(1); repx(i, 1, P){ // a の 冪 (mod P). cur *= a; cur %= P; // n が 見つかった. if(cur == 1){ n = i; break; } // 保存. H.insert(cur); } // 3. b の 冪乗 が H に含まれる m. int m = -1; repx(i, 1, P){ // b の 冪 (mod P). cur *= b; cur %= P; // n が 見つかった. if(H.count(cur)){ m = i; break; } } // 5. 例外(ハミルトン閉路 が 存在しない). if((LL)(P - 1) != (LL)n * (LL)m){ puts("No"); return 0; } // 6. ハミルトン閉路となるか? auto isHamiltonianCycle = [&](vl &v) -> bool { // 6-1. A[1], A[P] が, いずれも 1 か? if(v[0] != 1 || v[P - 1] != 1) return false; // 6-2. A[1] ~ A[P - 1] は, 1, 2, ...., P - 1 の 並び替えか? int p[P]; rep(i, P) p[i] = 0; rep(i, P - 1) ++p[(int)v[i]]; repx(i, 1, P) if(p[i] != 1) return false; // 6-3. 2 ~ P の i で, 指定された合同式を満たしているか? bool ok = true; repx(i, 1, P - 1){ if(v[i - 0] == v[i - 1] * a % P) continue; if(v[i - 1] == v[i - 0] * a % P) continue; if(v[i - 0] == v[i - 1] * b % P) continue; if(v[i - 1] == v[i - 0] * b % P) continue; ok = false; } // 6-4. 返却. return ok; }; // 7. n, m が 1. // 7-1. n = 1. if(n == 1){ vl ans; ans.pb(1); rep(i, P) ans.pb(ans.back() * b % P); assert(isHamiltonianCycle(ans)); puts("Yes"); rep(i, P) printf("%d%s", ans[i], (i < P - 1) ? " " : "\n"); return 0; } // 7-2. m = 1. if(m == 1){ vl ans; ans.pb(1); rep(i, P) ans.pb(ans.back() * a % P); assert(isHamiltonianCycle(ans)); puts("Yes"); rep(i, P) printf("%d%s", ans[i], (i < P - 1) ? " " : "\n"); return 0; } // 8. n, m > 1. // 8-1. m が 偶数. if(!(m & 1)){ vvl v(n, vl(m)); v[0][0] = 1; repx(i, 1, n) v[i][0] = v[i - 1][0] * a % P; rep(i, n) repx(j, 1, m) v[i][j] = v[i][j - 1] * b % P; vl ans; ans.pb(v[0][0]); rep(j, m){ if(j & 1) repr(i, n - 1, 1) ans.pb(v[i][j]); else repx(i, 1, n) ans.pb(v[i][j]); } repr(j, m - 1, 0) ans.pb(v[0][j]); assert(isHamiltonianCycle(ans)); puts("Yes"); rep(i, P) printf("%d%s", ans[i], (i < P - 1) ? " " : "\n"); return 0; } // 8-2. n が 偶数. if(!(n & 1)){ vvl v(m, vl(n)); v[0][0] = 1; repx(i, 1, m) v[i][0] = v[i - 1][0] * b % P; rep(i, m) repx(j, 1, n) v[i][j] = v[i][j - 1] * a % P; vl ans; ans.pb(v[0][0]); rep(j, n){ if(j & 1) repr(i, m - 1, 1) ans.pb(v[i][j]); else repx(i, 1, m) ans.pb(v[i][j]); } repr(j, n - 1, 0) ans.pb(v[0][j]); assert(isHamiltonianCycle(ans)); puts("Yes"); rep(i, P) printf("%d%s", ans[i], (i < P - 1) ? " " : "\n"); return 0; } 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 |
[入力例] 13 4 5 [出力例] Yes 1 5 11 3 12 9 7 4 6 8 2 10 1 ※AtCoderテストケースより ※但し, 上記のプログラムでは, 以下の内容が出力される. Yes 1 4 3 12 9 10 11 6 8 2 7 5 1 [入力例] 13 1 2 [出力例] Yes 1 2 4 8 3 6 12 11 9 5 10 7 1 ※AtCoderテストケースより [入力例] 13 9 3 [出力例] No ※AtCoderテストケースより [入力例] 13 1 1 [出力例] No ※AtCoderテストケースより [入力例] 19 20 22 [出力例] Yes 1 3 9 8 5 15 7 2 6 18 16 10 11 14 4 12 17 13 1 [入力例] 23 11 9 [出力例] Yes 1 11 6 20 13 5 9 7 8 19 2 22 12 17 3 10 18 14 16 15 4 21 1 [入力例] 37 12 21 [出力例] No [入力例] 211 314 159 [出力例] Yes 1 103 59 169 105 54 76 21 53 184 173 95 79 119 19 58 66 46 96 182 178 188 163 120 122 117 24 151 150 47 199 30 136 82 6 196 143 170 208 113 34 126 107 49 194 148 52 81 114 137 185 65 154 37 13 73 134 87 99 69 144 62 56 71 139 180 183 70 36 121 14 176 193 45 204 123 9 83 109 44 101 64 51 189 55 179 80 11 78 16 171 100 172 203 20 161 125 4 201 25 43 209 5 93 84 63 17 162 104 85 177 98 3 41 68 15 205 129 75 181 12 164 61 60 187 94 89 91 48 23 33 29 115 165 145 153 192 92 132 116 38 27 158 190 135 157 106 42 152 108 210 127 118 206 2 168 186 10 207 86 50 191 8 39 111 40 195 133 200 131 32 156 22 160 147 110 167 102 128 202 88 7 166 18 35 197 90 175 141 28 31 72 140 155 149 67 142 112 124 77 138 198 174 57 146 26 74 97 130 159 1 |
■参照サイト
AtCoder Regular Contest 118