けんちょんの競プロ精進記録

競プロの精進記録や小ネタを書いていきます

AtCoder ABC 230 B - Triple Metre (6Q, 灰色, 200 点)

実は愚直に文字列  T を作っても解ける!

問題概要

文字列  T を、"oxx" を  10^{5} 個連結した文字列とする。

与えられた文字列  S が、 T の部分文字列であるかどうかを判定せよ。

制約

  •  1 \le |S| \le 10

考えたこと

一般に、文字列  T が文字列  S を部分文字列にもつかどうかは次のように判定できる。


 i = 0, 1, \dots, |T| - |S| のいずれかに対して、

 T i 文字目から  |S| 文字分を切り取った部分文字列が  S に等しい


今回の問題も同様にすればよい。つまり、"oxx" を  10^{5} 個連結した文字列  T を作り、上記のことをすればよい。

もう少し効率化

上記の解法でも十分だが、もう少し効率化してみよう。まず、 T の周期性から、次のいずれかを満たすかどうかを判定するだけで十分であるといえる!


  •  T の 0 文字目から  |S| 文字分を切り取った部分文字列が  S に等しい
  •  T の 1 文字目から  |S| 文字分を切り取った部分文字列が  S に等しい
  •  T の 2 文字目から  |S| 文字分を切り取った部分文字列が  S に等しい

さらに、こうなれば、文字列  T の長さは  3 \times 10^{5} もある必要がない。 |S| よりも少し長い程度で十分だ。

具体的には、 T は "oxx" を 4 個連結したものであれば十分だ。

以上の解法を実装すると、下のコードのようになる。

コード

#include <bits/stdc++.h>
using namespace std;

int main() {
    string S, T;
    cin >> S;
    for (int i = 0; i < 4; i++) T += "oxx";

    bool res = false;
    for (int i = 0; i < 3; i++) {
        if (T.substr(i, S.size()) == S) res = true;
    }

    cout << (res ? "Yes" : "No") << endl;
}