KUPC 2014 G - Darkroom
問題
正整数n, dが与えられる。
長さnの0, 1からなる文字列を好きに出力することができる。
A, Bの二人が、この文字列のi番目, j番目に配置される。
ただし|i - j| = dとなるように置かれる。
A, Bに対して
- Aを左に1つ動かす
- Aを右に1つ動かす
- Bを左に1つ動かす
- Bを右に1つ動かす
のどれかの動きをさせることができる。(一度の指示では一人しか動かせない)
動きを行う前に、二人がいる場所の文字がそれぞれ与えられる。
質問を4回まで行って、i < jであるか、i > jであるかを確定せよ。
制約条件
n, d≦10^5
二人は両端から十分に離れた場所にいるので、動かして文字列の外に出ることはない。
二人の位置が途中で入れ替わることもない。
方針
dが3k+1, 3k+2と書けるのであれば、
100100100100...という文字列を最初に出力しておけば、
二人が右に一歩ずつ動けば、二人の座標がmod 3でわかる。
したがって、i + 1≡j (mod 3)であるか、i - 1≡j (mod 3)のどちらが成り立っているかわかり、i < j, i > jがわかる。
dが3の倍数の場合は、
00000/11111/10101/....というパターンを出力すればよい。
このパターンは、どこにいても右に1歩動けば、0000のエリア、1111のエリア、1010のエリア
かがわかる。
d = 3^p(3k + l)と書けるとき、
各パターンの長さを3^pにすれば、必ず二人は違うエリアに入るので、3の倍数と同じ原理でi < j, i > jのどちらかがわかる。
ソースコード
int get(const string &s){ if(s == "000" || s == "001" || s == "011") return 0; if(s == "111" || s == "110") return 1; return 2; } int main(){ int n, d; cin >> n >> d; string s(n, '0'); if(d % 3){ rep(i, n) if(i % 3 == 0) s[i] = '1'; cout << s << endl; int a = -1, b = -1; rep(i, 3){ string x, y; cin >> x >> y; if(x == "1") a = i; if(y == "1") b = i; if(i < 2){ cout << "Move(A,-1)" << endl; cin >> x >> y; cout << "Move(B,-1)" << endl; } } if((a + d) % 3 == b % 3) cout << "i<j" << endl; else cout << "i>j" << endl; return 0; } int t = 1; while(d % 3 == 0) d /= 3, t *= 3; for(int i = 0; i < n; ){ rep(j, t) if(i < n) s[i++] = '0'; rep(j, t) if(i < n) s[i++] = '1'; rep(j, t) if(i < n) s[i++] = '1' - j % 2; } cout << s << endl; string a, b; rep(i, 3){ string x, y; cin >> x >> y; a += x; b += y; if(i < 2){ cout << "Move(A,1)" << endl; cin >> x >> y; cout << "Move(B,1)" << endl; } } int ia = get(a), ib = get(b); if((ia + d) % 3 == ib % 3) cout << "i<j" << endl; else cout << "i>j" << endl; return 0; }