Codeforces Round #641 (Div. 2) D - Orac and Medians 解説
問題概要
長さの数列について、以下の操作を繰り返し全ての要素をにできるか判定せよ。
解説
色々実験してみると、大きい操作の前に小さい操作で代替の操作が実現可能であることがわかる。
区間の長さをとしたとき、その区間に操作をすると、その区間の要素を全て小さい方に変えることができる。
以下のような数列に置き換えて考える。(中央値であり、に合わせられるかを考える問題なので、との大小関係以外の情報は無駄である)
のとき
のとき
のとき
まず、少なくとも1つはがないといけないので、それを仮定する。
このとき、連続する要素がのとき、にでき、そこを起点として全ての要素をにできる。
連続する要素がのときも同様である。
また、すべてのの隣がの場合、の隣をにすることができればそこを起点として同様に達成可能である。
の隣にを持ってくるために必要なのは、連続する2要素が、または連続する3要素がの場合である。それらの区間を起点として、をの隣まで移動させればよい。
長さの区間については、上記の条件を確認することと同様なので、まで確認すれば十分である。同様に、長さ以上についても言えるので、長さまでの条件を考えればよいことになる。
上記の条件をまとめると、
少なくとも一つはが存在する
ある連続する3要素がである
となるので、それを実装すればよい。
void solve() { int N, K; cin >> N >> K; vec<int> A(N), B(N); rep(i, N) { cin >> A[i]; if (A[i] < K) B[i] = 0; if (A[i] == K)B[i] = 1; if (A[i] > K) B[i] = 2; } bool exist = false; rep(i, N)if (B[i] == 1)exist = true; //一個もKがなかったらダメ if (not exist) { cout << "no" << endl; return; } //1個以上はある状態 bool ok = false; if (N == 1)ok = true; else if (N == 2) { sort(all(B)); if (B[0] && B[1]) ok = true; } // N > 3 else { for (int i = 0; i + 2 < N; i++) { vector<int> C; C.push_back(B[i]); C.push_back(B[i + 1]); C.push_back(B[i + 2]); sort(all(C)); if(C[0] == 0 && C[1] == 1 && C[2] == 1)ok = true; if(C[0] == 0 && C[1] == 1 && C[2] == 2)ok = true; if(C[0] == 0 && C[1] == 2 && C[2] == 2)ok = true; if(C[0] == 1 && C[1] == 1 && C[2] == 1)ok = true; if(C[0] == 1 && C[1] == 1 && C[2] == 2)ok = true; if(C[0] == 1 && C[1] == 2 && C[2] == 2)ok = true; if(C[0] == 2 && C[1] == 2 && C[2] == 2)ok = true; } } cout << (ok ? "yes" : "no") << endl; } int main() { int t; cin >> t; while (t--) solve(); }