公式
B - 本棚の並び順 / Order of Books on the Bookshelf 解説
by
解説 【注意】本問題は433点以上の難易度であると思われます。
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;
}
