Educational Codeforces Round 101 - E. A Bit Similar
酒入ってたけど、入ってなくても思いつかなかったな。
問題概要
つの 文字列で 文字でも一致する状態を "a bit similar" であるとする。
文字列 が与えられたとき、 から得られる長さ の部分文字列すべてに対して "a bit similar" である辞書順最小の 文字の文字列を求める。(なければ "NO" と答える。)
テストケースは 個与えられる。
補足 : 部分文字列は、文字列の連続する部分列のことである。
制約
解法
と を反転した文字列を考える。
この文字列に現れる長さ の部分文字列は、題意を満たさないと言える。
例えば、"0110" を反転させた "1001" を見てみる。( とする。)
文字ずつスライドしてみていくと、
0110
1001
0110
1001
0110
1001
となっていて、反転前の部分文字列を見ると "a bit similar" でないので、確かに題意を満たさない。
ただ、 文字列を考えているので、それぞれ 文字でも異なっていれば、"a bit similar" でなかったものは "a bit similar" となる。
このことから、反転させた文字列から取れる部分文字列に含まれていない長さ の文字列は、題意を満たす。
したがって、出現した部分文字列を管理して、出現しなかった辞書順最小のものを答えとすればよい。(すべて出現していれば "NO" となる。)
( 進表記で見ると、mex (集合に含まれない最小の数) を の範囲内で求めることと同じ。)
ただ、そのまま実装にうつると、部分文字列の列挙に かかって大変なことになるので、もう一工夫する必要がある。
部分文字列の個数は 個あるが、この個数は制約から で抑えられる。
よって、 の場合は先頭 文字を で埋めても問題はない。(自由度を下位 桁に制限しても、 通りあるので、必ず解が存在して "YES" となる。)
考慮すべきなのは、先頭 文字が である部分文字列の下位 文字であり、これを集合に追加すればよい。(先頭に が含まれていれば、その時点で求めようとしている文字列と反転前の部分文字列とは "a bit similar" になるので、考慮する必要はない。)
コード
#include <iostream> #include <string> #include <set> #include <vector> using namespace std; void solve(){ int n, k; string s; cin >> n >> k >> s; // '0' '1' 反転 for(int i = 0; i < n; ++i) s[i] = s[i] == '0' ? '1' : '0'; // 出現した部分文字列を 2 進数として集合で管理 set<int> st; if(k <= 20){ for(int i = 0; i + k <= n; ++i){ st.emplace(stoi(s.substr(i, k), nullptr, 2)); } } else{ vector<int> zeros(n + 1); for(int i = 0; i < n; ++i){ zeros[i + 1] = zeros[i] + (s[i] == '0'); } for(int i = 0; i + k <= n; ++i){ // 先頭 (k - 20) 文字が 0 で埋まっていれば、集合に要素を追加 if(zeros[i + k - 20] - zeros[i] == k - 20){ st.emplace(stoi(s.substr(i + k - 20, 20), nullptr, 2)); } } } // mex を求める int ans = -1; for(int num = 0; num < 1 << min(k, 20); ++num){ // num が集合になければ ans を保存してループを抜ける if(st.find(num) == st.end()){ ans = num; break; } } if(ans == -1) cout << "NO\n"; else{ cout << "YES\n"; for(int i = 0; i < k - 20; ++i) cout << 0; for(int i = min(k, 20) - 1; i >= 0; --i) cout << (ans >> i & 1); cout << '\n'; } } int main(){ int q; cin >> q; while(q--) solve(); return 0; }
雑記
コンテスト後に解法ツイートを眺めていたが、どうしてビット列を反転させているのかしばらく分からなかった。
難しい。