コーナーケース見落としてた…。
https://yukicoder.me/problems/no/2254
問題
N要素の整数列A,Bと正整数Kが与えられる。
AからK要素以上の連続部分列を指定し、反転することができるとき、AをBに一致させることができるか判定せよ。
解法
まずコーナーケースを片付ける。
初期状態でA=BならYes。
AとBそれぞれ多重集合とみなして一致しないならNo。
その他のケースは、ここからKの大小で場合分けする。
- K>Nだと反転できないのでNo。
- K=Nの場合、A全体を反転させてBと一致できるか判定する。
- K<N-1の場合、任意の2要素をswapできるので、Yes。
- K=N-1の場合、できるのは全体のシフトと反転である。よってZ-algorithmを使いBをシフトしたものがAまたはAの反転と一致するか判定するとよい。
int N,K; vector<int> A,B; int C[202020]; using VT = vector<int>; vector<int> Zalgo(VT s) { vector<int> v(1,s.size()); for(int i=1,l=-1,r=-1;i<s.size();i++) { if(i<=r && v[i-l]<r-i+1) v.push_back(v[i-l]); else { l=i; r=(i>r)?i:(r+1); while(r<s.size() && s[r-i]==s[r]) r++; v.push_back((r--)-l); } } v.push_back(0); return v; } void solve() { int i,j,k,l,r,x,y; string s; cin>>N>>K; A.resize(N); B.resize(N); FOR(i,N) { cin>>A[i]; C[A[i]]++; } FOR(i,N) { cin>>B[i]; C[B[i]]--; } FOR(i,N) if(A[i]!=B[i]) break; if(i==N) { cout<<"Yes"<<endl; return; } FOR(i,202020) if(C[i]) { cout<<"No"<<endl; return; } if(K>N) { cout<<"No"<<endl; } else if(K==N) { FOR(i,N) if(A[i]!=B[N-1-i]) break; if(i==N) { cout<<"Yes"<<endl; } else { cout<<"No"<<endl; } } else if(K==N-1) { FOR(i,2) { reverse(ALL(A)); vector<int> D; FOR(j,N) D.push_back(A[j]); FOR(j,N) D.push_back(B[j]); FOR(j,N) D.push_back(B[j]); auto v=Zalgo(D); FOR(j,N) if(v[j+N]>=N) { cout<<"Yes"<<endl; return; } } cout<<"No"<<endl; } else { cout<<"Yes"<<endl; } }
まとめ
K=N-1のケースを見事に見逃した…。