Official

F - Error Correction Editorial by leaf1415


\(S_i\)\(T\) と等しい可能性があるか、つまり、\(T \coloneqq S_i\) とおいたとき、問題文中の \(4\) つの条件のいずれかを満たすか判定することを考えます。本問題を解くには各 \(i\) についてこれを行えば良いです。

\(T \coloneqq S_i\) とおきます。 \(T\)\(T'\) が先頭から見て何文字目まで一致するかを調べ、一致する最大の長さを \(A\) とおきます。 同様に、\(T\)\(T'\) が末尾から見たときに一致する最大の長さを \(B\) とおきます。 例えば、abcdabcdacd は、先頭から見ると abc\(3\) 文字までが一致し、末尾から見ると cd\(2\) 文字までが一致します。

このとき、問題文中の \(4\) つの条件はそれぞれ、\(A, B\) および、\(T\)\(T'\) の長さ \(|T|, |T'|\) によって下記の通りに言い換えられます。

  • \(T'\)\(T\) と等しい:\(A = B = |T| = |T'|\)
  • \(T'\)\(T\) のいずれか \(1\) つの位置(先頭と末尾も含む)に英小文字を \(1\) つ挿入して得られる文字列である:\(A+B \geq |T| = |T'|-1\)
  • \(T'\)\(T\) からある \(1\) 文字を削除して得られる文字列である:\(A+ B \geq |T|-1 = |T'|\)
  • \(T'\)\(T\) からある \(1\) 文字を別の英小文字に変更して得られる文字列である:\(A +B = |T| -1 = |T'| - 1\)

よって、\(A, B, |T|, |T'|\) が上記の \(4\) つのいずれかの条件を満たすかを実際に判定すれば良いです。

以下に、C++ 言語による本問題の正解例を記載します。

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;

ll n;
string s[500001], t2;
ll a[500001], b[500001];

ll calc(const string &s, const string &t)
{
  for(int i = 0; i < (int)t.size(); i++){
    if(i >= s.size()) return s.size();
    if(s[i] != t[i]) return i;
  }
  return t.size();
}

int main(void){
  cin >> n >> t2;
  for(int i = 1; i <= n; i++) cin >> s[i];

  for(int i = 1; i <= n; i++) a[i] = calc(s[i], t2);
  reverse(t2.begin(), t2.end());
  for(int i = 1; i <= n; i++){
    reverse(s[i].begin(), s[i].end());
    b[i] = calc(s[i], t2);
  }
  
  vector<ll> ans;
  for(int i = 1; i <= n; i++){
    const string &t = s[i];
    bool flag = false;
    if(a[i] == t.size() && t.size() == t2.size()) flag = true;
    if(a[i]+b[i] >= t.size() && t.size()+1 == t2.size()) flag = true;
    if(a[i]+b[i] >= t.size()-1 && t.size()-1 == t2.size()) flag = true;
    if(a[i]+b[i] == t.size()-1 && t.size() == t2.size()) flag = true;
    if(flag) ans.push_back(i);
  }
  
  cout << ans.size() << endl;
  for(auto x : ans) cout << x << " ";
  cout << endl;
  
  return 0;
}

posted:
last update: