実行時間制限: 2 sec / メモリ制限: 1024 MB / Difficulty: 228
問題概要
英子文字からなる長さの等しい2つの文字列 が与えられる。 を空の配列として、以下の操作を が等しくなるまで繰り返す。
- の文字を1文字書き換え、 の末尾に を追加する。
こうして得られる文字列の配列 のうち、要素数最小かつ辞書順最小のものを求めよ。
制約
- の長さは 以上 以下。
考察
問題の意味がいまいちつかみにくいので、サンプルケース1 (adbe
, bcbc
) でいろいろ試してみる。以下では、 の長さを とする。
要素数最小ということは文字の入れ替え回数が最小ということなので、「 に対して、 [tex :S_i \neq T_i] ならば操作を行う」という方針が基本となる。
ただし、単純にこの方針をとると
bdbe
, bcbe
, bcbc
のようになり、この は辞書順最小でない。
ここで、1回の操作で置き換える文字によって がどのように変わるかを考えてみる。
adbe
の1文字目をa
からb
に置き換える :bdbe
は元の文字列より辞書順が後ろになる。adbe
の2文字目をd
からc
に置き換える :acbe
は元の文字列より辞書順が前になる。
つまり、辞書順最小を目指すためには 「 のときに置き換えを実行し、そうでないときは行わない」という方針で とした後に「 のときに置き換えを実行し、そうでないときは行わない」という方針で とすればよいことになる。
計算量は で、今回の制約下では高速に動作する。
コードではdiff
という配列に と の辞書順での差を格納しており、値が正なら の方が辞書順後ろ、負ならば辞書順前ということを表している。
コード
#include <bits/stdc++.h> using namespace std; #define rep(i, start, end) for (auto i = (start); (i) < (end); (i)++) #define rrep(i, start, end) for (auto i = (start); (i) >= (end); (i)--) // ======================================== // int main() { string S, T; cin >> S >> T; int l = S.size(); vector<int> diff(l, 0); rep(i, 0, l) diff[i] = S[i] - T[i]; vector<bool> changed(l, false); vector<string> X; rep(i, 0, l) { if (!changed[i] && diff[i] > 0) { S[i] = T[i]; X.push_back(S); changed[i] = true; continue; } } rrep(i, l - 1, 0) { if (!changed[i] && diff[i] < 0) { S[i] = T[i]; X.push_back(S); changed[i] = true; continue; } } cout << X.size() << endl; for (auto x : X) cout << x << endl; }
実装時間: 20分