これすごく好き!!!普通に難しい。
問題概要
'o' と 'x' のみからなる長さ の文字列 を作りたい。部品として使えるのは以下のものたち ( となっている)。
- "ox" が 個
- "xo" が 個
- "o" が 個
- "x" が 個
これらを適切な順序で concat することで、文字列 にすることが可能かどうかを判定せよ。
制約
考えたこと
とりあえず、 に含まれる 'o' が 個、'x' が 個になる必要がある。
それを満たしているとき、部品 "o" と "x" の配置はあとからいくらでも調整が効くので、なるべく "ox" と "xo" を積極的に消費していきたい。逆に 個の "ox" と 個の "xo" をすべて、 上で、互いに重なり合わないように配置できたならば、残りは "o" と "x" で埋めることができる。
さて、 において、「"o" が連続している箇所」や「"x" が連続している箇所」に仕切りを入れて分割して考えることにしよう。(仕切りを入れる場所には "ox" や "xo" は配置できない)。そうすると各区間は
- "oxox...ox"
- "xoxo...xo"
- "oxox...o"
- "xoxo...x"
のいずれかのパターンとなる。それぞれについて、長さを (パターン 1, 2) または (パターン 3, 4) とする。このとき、"ox" と "xo" の消費可能数を で表すことにすると、
- と () が可能
- と () が可能
- () が可能
- () が可能
というふうになる。基本的には、どのパターンからも合計 個ずつ作れることがわかる (そして合計が になるような 2 数のパターンは任意)。よって、各区間ごとの「(長さ - 1) / 2」の合計値を としたとき、 であれば可能と言える。
となる場合が問題となる。このときは、パターン 1 で を選んだり、パターン 2 で を選んだりすることによって、"ox" と "xo" の消費量の合計値を上手に上げていく必要がある。ただし、
- パターン 1 で を選ぶならば、それを選んだ の合計値が を超えてはならない
- パターン 2 で を選ぶならば、それを選んだ の合計値が を超えてはならない
ということに留意する必要がある。以上から、次のように判定できることがわかる。
まず、すべてのパターンの「(長さ - 1) / 2」の合計値を とする。
パターン 1 な区間をすべて抽出して、それらの長さを とする。それらから合計値 / 2 が 以下となるように選べる個数の最大値を とする
パターン 2 な区間をすべて抽出して、それらの長さを とする。それらから合計値 / 2 が 以下となるように選べる個数の最大値を とする
このとき、 ならば可能で、そうでなければ不可能である。
計算量は となる。
コード
#include <iostream> #include <vector> #include <string> #include <algorithm> using namespace std; long long N, A, B, C, D; string S; bool solve() { int maru = 0; for (int i = 0; i < N; ++i) if (S[i] == 'o') ++maru; if (maru != A + B + C) return false; if (N - maru != A + B + D) return false; vector<long long> ox, xo, other; for (int i = 0; i < N;) { int j = i+1; while (j < N && S[j-1] != S[j]) ++j; if ((j-i) % 2 == 0) { if (S[i] == 'o') ox.push_back((j-i)/2); else xo.push_back((j-i)/2); } else other.push_back((j-i)/2); i = j; } sort(ox.begin(), ox.end()); sort(xo.begin(), xo.end()); int num = 0; long long oxsum = 0, xosum = 0, otsum = 0; for (int i = 0; i < ox.size(); ++i) { if (oxsum + ox[i] <= A) ++num; oxsum += ox[i]; } for (int i = 0; i < xo.size(); ++i) { if (xosum + xo[i] <= B) ++num; xosum += xo[i]; } for (int i = 0; i < other.size(); ++i) otsum += other[i]; if ((oxsum - (int)ox.size()) + (xosum - (int)xo.size()) + otsum + num >= A + B) return true; return false; } int main() { while (cin >> N >> S >> A >> B >> C >> D) { if (solve()) cout << "Yes" << endl; else cout << "No" << endl; } }