0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

AtCoderログ:0085 - ABC 049 C

Last updated at Posted at 2021-08-20

問題

問題文

英小文字からなる文字列 $S$ が与えられます。$T$ が空文字列である状態から始め、以下の操作を好きな回数繰り返すことで $S=T$ とすることができるか判定してください。
・$T$ の末尾に dream dreamer erase eraser のいずれかを追加する。

制約

・$1 \le |S| \le 10^5$
・$S$ は英小文字からなる。

収録されている問題セット

回答

回答1 (AC)

与えられた文字列 $S$ を先頭から調べてみます。先頭に "eraser" という文字列があれば、それは eraser として確定できます。先頭が eraser ではないことが確定した状態で戦闘に "erase" という文字列があれば、それは erase として確定できます。この順番はとても重要で、逆に先頭に "erase" という文字列を見つけても、これは erase なのか eraser (の一部)なのかを確定することが出来ません。

同様に dreamer と dream についても調べるのですが、ちょっとややこしくなります。先頭に dreamer という文字列があったとしても、それは dreamer である可能性と、dream + er... である可能性があります。dreamer であることが確定できるのは、先頭の文字列が dreamerd 又は dreamere の場合です。同様に、先頭からの文字列が dreamd または dreame の場合には dream であることが確定出来ます。なお、このままでは s="dreamer" または s="dream" の場合を検出できないので、条件式に追加する必要があります。

以上をまとめたコードは以下のようになりました。文字列 s に対し、ss にコピーを保持し、文字列 s の先頭が eraser/erase/dreamer/dream であるかを判別し、そうである場合には s から先頭部分を削除しています。一通りのチェックが終わった段階で文字列 s に変化がない (つまり s=ss) の場合には、NO と出力して終了します。文字列 s がだんだん短くなり、s="" となるまで削除できれば YES を出力して終了となります。

abc049c-1.cpp
#include <bits/stdc++.h>
using namespace std;
 
int main() {
  string s;
  cin >> s;
 
  string answer = "YES";
  while ( s!="" ) {
    string ss = s;
    if ( s.find("eraser")==0 ) {
      s = s.erase(0,6);
    } else if ( s.find("erase")==0 ) {
      s = s.erase(0,5);
    } else if ( s=="dream" || s=="dreamer" ) {
      s = "";
    } else if ( s.find("dreamerd")==0 || s.find("dreamere")==0 ) {
      s = s.erase(0,7);
    } else if ( s.find("dreamd")==0 || s.find("dreame")==0 ) {
      s = s.erase(0,5);
    }
    
    if ( ss==s ) {
      answer = "NO";
      break;
    }
  }

  cout << answer << endl;
}

回答2 (AC)

この問題のややこしい点は、使用している $4$ 種類の文字列 erase/eraser/dream/dreamer がお互いに似ているところです。そこで、これら文字列を逆から考えることにすると、文字列 s を逆順にした文字列 s' が esare/resare/maerd/remaerd という文字列からだけで構成できるか?を調べれば良いことになります。ありがたいことに新しい4つの文字列は文字の並びの重複が少ないので、文字列 s' の冒頭から調べるのがとても簡単になります。コードは以下のようになりました。

abc049c-2.cpp
#include <bits/stdc++.h>
using namespace std;
 
int main() {
  string s;
  cin >> s;

  string answer = "YES";
  while ( s!="" ) {
    string ss = s;
    if ( s.find("esare")==0 || s.find("maerd")==0 ) {
      s = s.erase(0,4);
    } else if ( s.find("resare")==0 ) {
      s = s.erase(0,5);
    } else if ( s.find("remaerd")==0 ) {
      s = s.erase(0,6);
    }

    if ( ss==s ) {
      answer = "NO";
      break;
    }
  }

  cout << answer << endl;
}

調べたこと

AtCoder に登録したら次にやること第09問の解説

回答2と同じ方針でした。

AtCoder の解説公式解説

回答2と同じ方針でした。

リンク

前後の記事

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?