NCPC 14 H Clock Picture 序列同構,KMP
阿新 • • 發佈:2018-11-02
題意:兩個鐘面上有n個針,第i個角度分別為a[i],b[i]. 總的角度為mod=360000.
n<=2e5. 0<=a[i]<360000. 問能否將鍾a上的針同時旋轉一個角度後變為鍾b.
現將兩個鍾排序. 假如a[i]變為b[j]. 則旋轉角度為p=(b[j]-a[i]+mod)%mod;
此時b[j+1]必須要由a[i+1]旋轉後得到. ([1.i-1]顯然角度不夠, [i+2,n] 若得到b[j+1] 則a[i+1]落在b[j],b[j+1]之間,沒有匹配)
所以 (a[i]+p)%mod=b[j] (a[i+1]+p)%mod =b[j+1] 相減得到 a[i+1]-a[i] ≡ b[j+1]-b[j] (mod 36000)
現在求出s[i],t[i]分別表示序列a,b的相鄰差.並把序列t複製一遍.
若a[1]旋轉為b[j]後,序列a會和b相同.等價於序列s和t[j,j+n-1]相同. 做一次kmp即可.
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=4e5+5,mod=360000; int n,a[N],b[N],s[N],t[N]; int fail[N]; void getfail(){ // memset(fail,0,sizeof(fail)); fail[0]=-1; fail[1]=0; for(int i=2;i<=n;i++){ int p=fail[i-1]; while(p>=1&&s[p+1]!=s[i]) p=fail[p]; fail[i]=p+1; } } void kmp(){ bool flag=false; getfail(); for(int i=1,p=1;i<=n*2;i++){ while(p>=1&&s[p+1]!=t[i])p=fail[p]; ++p; if(p==n) flag=true; } puts(flag?"possible":"impossible"); } int main(){ cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) cin>>b[i]; sort(a+1,a+1+n); sort(b+1,b+1+n); a[n+1]=a[1]; b[n+1]=b[1]; for(int i=1;i<=n;i++){ s[i]=(a[i+1]-a[i]+mod)%mod; t[i]=(b[i+1]-b[i]+mod)%mod; } // for(int i=1;i<=n;i++) printf("%d%c",s[i],i==n?'\n':' '); // for(int i=1;i<=n;i++) printf("%d%c",t[i],i==n?'\n':' '); for(int i=1;i<=n;i++) t[i+n]=t[i]; kmp(); return 0; }