BZOJ4044 : [Cerc2014] Virus synthesis

设f[x]表示得到x这个回文串的最小步数,则ans=min(n-len[x]+f[x])

边界条件f[长度为0的偶回文串]=1

因为翻转只会得到偶回文串,所以f[奇回文串]=该串的长度

对于一个偶回文串x,设y为x去掉首尾得到的串,有f[x]=f[y]+1

设y为长度不超过x的一半的x的最长回文后缀,有f[x]=len[x]/2-len[y]+f[y]+1

两种情况取个最小值即可。

对于状态的表示以及最长回文后缀的询问,用回文树支持操作即可。时间复杂度$O(n)$。

 

#include<cstdio>
#include<cstring>
const int N=100010,S=4;
int T,n,i,x,y,ans,all,son[N][S],fail[N],trans[N],f[N],len[N],text[N],last,tot,q[N],h,t;char s[N];
inline int newnode(int l){
  for(int i=0;i<S;i++)son[tot][i]=0;
  len[tot]=l;
  return tot++;
}
inline void init(){
  last=tot=all=0;
  newnode(0),newnode(-1);
  text[0]=-1,fail[0]=1;
}
inline int getfail(int x){
  while(text[all-len[x]-1]!=text[all])x=fail[x];
  return x;
}
inline void add(int w){
  text[++all]=w;
  int x=getfail(last);
  if(!son[x][w]){
    int y=newnode(len[x]+2);
    fail[y]=son[getfail(fail[x])][w];
    if(len[y]<=2)trans[y]=fail[y];else{
      int z=trans[x];
      while(text[all-len[z]-1]!=text[all]||(len[z]+2)*2>len[y])z=fail[z];
      trans[y]=son[z][w];
    }
    son[x][w]=y;
  }
  last=son[x][w];
}
inline int hash(char c){
  if(c=='A')return 0;
  if(c=='T')return 1;
  if(c=='C')return 2;
  return 3;
}
inline void up(int&a,int b){if(a>b)a=b;}
int main(){
  for(scanf("%d",&T);T--;printf("%d\n",ans)){
    scanf("%s",s+1),ans=n=std::strlen(s+1);
    for(init(),i=1;i<=n;i++)add(hash(s[i]));
    for(i=2;i<tot;i++)if(len[i]&1)f[i]=len[i];
    f[q[h=t=0]=0]=1;
    while(h<=t)for(x=q[h++],i=0;i<4;i++)if(son[x][i]){
      f[y=son[x][i]]=f[x]+1;
      up(f[y],len[y]/2-len[trans[y]]+f[trans[y]]+1);
      up(ans,n-len[y]+f[y]);
      q[++t]=y;
    }
  }
  return 0;
}

  

posted @ 2015-08-03 22:38  Claris  阅读(961)  评论(0编辑  收藏  举报