置換の問題で添え字をバグらせない
色々雑です
縦線 本から成るあみだくじの上部に と番号を割り振って、それらを辿って下部に番号を書き込んだとします。このときの下部の左から 番目の番号を とします。
このあみだくじが表す置換は ではありません。
が表しているのは 番目に来る数であって、 の行き先ではないからです。(これややこしくないですか???)
つまり、このあみだくじが表す置換を とすると、
- は「 が左から何番目に行くか」
- は「左から 番目に来る数は何か」
を表しています。
これを踏まえると、 に対して です。
ところで、これは逆元の定義そのものです。
(意味を考えれば明らかではありますが)
これを意識することで見通しが良くなる場合があります。
例えばあるあみだくじがあり、それが表す置換が であるとします。
このあみだくじ最下部の、左から 番目と 番目の間に横線を引いたあみだくじの置換 を考えます。
先程述べたように逆元を取ると位置を表す置換に変換されるので、逆元に変換→swap→逆元に変換とします。
を「置換を表す配列の左から 番目と 番目を swap する」ことに対応する互換とすると、
です。
なので結局、あみだくじに線を引く(左から互換 を掛ける)操作は、右から互換 を掛けることと等価であるとわかりました。
ABC013D - 阿弥陀
あみだくじが表す置換が求まれば後はダブリングするだけです。
通常であれば置換を表す配列 だけでなく が のどこにあるのかも保持しなければなりませんが、先程の事柄を踏まえることで不要となります。
上から 番目の横線が表す互換を とします。
あみだくじの表す置換は ですが、これは に対し の順に を swap するだけで求まります。
#include <bits/stdc++.h> using namespace std; vector<int> inv(const vector<int> &p) { vector<int> q(p.size()); for (int i = 0; i < p.size(); i++) q[p[i]] = i; return q; } vector<int> compose(const vector<int> &q, const vector<int> &p) { vector<int> r(p.size()); for (int i = 0; i < p.size(); i++) r[i] = q[p[i]]; return r; } int main() { int n, m, d; cin >> n >> m >> d; vector<int> p(n); iota(p.begin(), p.end(), 0); vector<int> a(m); for (int i = 0; i < m; i++) cin >> a[i], a[i]--; for (int i = m - 1; i >= 0; i--) swap(p[a[i] + 1], p[a[i]]); // ダブリング vector<int> ans(n); iota(ans.begin(), ans.end(), 0); for (int k = 0; k < 30; k++) { if ((1 << k) & d) ans = compose(p, ans); p = compose(p, p); } for (int i = 0; i < n; i++) cout << ans[i] + 1 << "\n"; }
Submission #29633662 - AtCoder Beginner Contest 013
yukicoder No.326 あみだますたー
はじめに を対称群の逆元 に変換しておくと、あみだくじの下部の番号の列を にできるか?という問題になり、扱いやすくなります。
#include <bits/stdc++.h> using namespace std; vector<int> inv(const vector<int> &p) { vector<int> q(p.size()); for (int i = 0; i < p.size(); i++) q[p[i]] = i; return q; } int main() { int n, k; cin >> n >> k; vector<int> b(n); iota(b.begin(), b.end(), 0); for (int i = 0; i < k; i++) { int x, y; cin >> x >> y; x--, y--; swap(b[x], b[y]); } vector<int> a(n); for (int i = 0; i < n; i++) cin >> a[i], a[i]--; a = inv(a); vector<pair<int, int>> ans; for (int i = 0; i < n; i++) { if (b[i] == a[i]) continue; int j; for (j = i + 1; j < n; j++) { if (a[i] == b[j]) break; } for (int k = j - 1; k >= i; k--) { ans.push_back({k + 1, k + 2}); swap(b[k], b[k + 1]); } } cout << ans.size() << "\n"; for (auto p : ans) cout << p.first << " " << p.second << "\n"; }