公式

B - 本棚の並び順 / Order of Books on the Bookshelf 解説 by physics0523

解説 【注意】本問題は433点以上の難易度であると思われます。

本問題の難易度は配点の 300 点に対して非常に難しいと想定されています。恐らく、 433 点以上の難易度であると思われます。


\(A[l,r]\) を \(A_l,A_{l+1},\dots,A_r\) をこの順に連結した列であるとします。

\(A[1,M], A[2,M+1], \dots, A[N-M+1,N]\) がそれぞれ \(B\) と一致するかを判定すればよいです。
しかしながら、愚直に判定しているようでは時間計算量が \(O(NM)\) かかり実行時間制限に間に合いません。

様々な方法がありますが、ACL にも実装されている z-algorithm を用いるのが便利です。
z-algorithm を用いると、文字列 \(S\) に対し、 \(S[1,|S|]\) と \(S[i,|S|]\) とが先頭何文字まで一致するかを全ての \(1 \le i \le |S|\) について \(O(|S|)\) で知ることができます。これを応用しましょう。

z-algorithm に \(B,A\) をこの順に連結した列を尋ねましょう(この列を \(S\) とします)。
すると、 \(S[1,|S|]\) と \(S[M+i,|S|]\) とが先頭 \(M\) 文字以上一致する、またその時に限り、 \(A[i,i+M-1]\) と \(B\) とが一致することが分かります。

全体で時間計算量 \(O(N+M)\) でこの問題に正解できます。

実装例 (C++):

#include<bits/stdc++.h>
#include<atcoder/string>

using namespace std;
using namespace atcoder;

int main(){
  int N,M;
  cin >> N >> M;
  vector<int> A(N),B(M);
  for(auto &nx : A){cin >> nx;}
  for(auto &nx : B){cin >> nx;}
  vector<int> s=B;
  for(auto &nx : A){s.push_back(nx);}
  auto z=z_algorithm(s);
  for(int i=0;i<N;i++){
    if(z[M+i]>=M){
      cout << i+1 << "\n";
      return 0;
    }
  }
  cout << "-1\n";
  return 0;
}