BZOJ3084 : [Algorithmic Engagements 2011]The Shortest Period

Claris發表於2016-02-20

列舉答案長度$L$,設$A$和$B$分別為第一個迴圈節和反串的第一個迴圈節。

1.壞點不在$A$,那麼可以暴力匹配檢驗。

2.壞點不在$B$,那麼把串翻轉後不在$A$中,轉化為1。

3.壞點在$A$和$B$的交裡面,那麼只要長度為$n-L+1$的前字尾相同,那麼就存在長度為$L$的迴圈節。

通過擴充套件kmp和Hash快速判斷即可,時間複雜度$O(dn\log n)$。

 

#include<cstdio>
const int N=200010,P=233;
int T,n,i,j,t,k,p,l,ans,g[N];char a[N];unsigned int pow[N],f[N];
inline void swap(char&a,char&b){char c=a;a=b;b=c;}
inline unsigned int hash(int l,int r){return f[r]-f[l-1]*pow[r-l+1];}
inline int min(int a,int b){return a<b?a:b;}
void solve(){
  for(i=1;i<=n;i++)f[i]=f[i-1]*P+a[i];
  for(g[i=0]=n;i<n-1&&a[i+1]==a[i+2];i++);
  for(g[t=1]=i,k=2;k<n;k++){
    p=t+g[t]-1,l=g[k-t];
    if(k+l>p){
      j=(p-k+1)>0?(p-k+1):0;
      while(k+j<n&&a[k+j+1]==a[j+1])j++;
      g[k]=j,t=k;
    }else g[k]=l;
  }
  for(i=n;i;i--)g[i]=g[i-1];
  for(i=1;i<ans;i++){
    j=g[i+1];
    if(j==n-i||g[i+2]>=n-i+1)ans=i;else{
      j+=i+2,k=(j-2)/i*i+1,t=k+i;
      if(t>n)t=n;
      if(hash(j,t)!=hash(j-k,t-k)||g[t+1]<n-t)continue;
      for(t++;t<=n;t+=i)if(g[t]<min(i,n-t+1))break;
      if(t>n)ans=i;
    }
  }
}
int main(){
  for(pow[0]=i=1;i<N;i++)pow[i]=pow[i-1]*P;
  scanf("%d",&T);
  while(T--){
    scanf("%d%s",&n,a+1);
    ans=n-1;
    solve();
    for(i=1;i<n-i+1;i++)swap(a[i],a[n-i+1]);
    solve();
    printf("%d\n",ans);
  }
  return 0;
}

  

相關文章