回文自动机上dp
f[x]表示形成x代表的回文串所需的最小步数,
若len[x]为奇数,f[x]=len[x],因为即使有更优的,也是直接添加,没有复制操作,那样就不用从x转移了。
若len[x]为偶数,f[x]=min(f[fa[x]]+1,len[x]/2-len[fro[x]]+f[fro[x]]+1),因为fa[x]肯定是最后复制更优,那么将复制前的子串末尾加一个字符即可,fro则是len不大于len[x]/2的最长的x的fail.
memsetT死了,改成每次只memset用的就过了
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define N 100050 5 using namespace std; 6 int len[N],ch[N][5],nxt[N],fro[N],f[N]; 7 int T,n,ans,last,tot; 8 char s[N]; 9 inline void init(){ 10 ans=0x7fffffff; 11 last=0;tot=1; 12 memset(ch[0],0,sizeof ch[0]); 13 memset(ch[1],0,sizeof ch[1]); 14 nxt[0]=nxt[1]=1; 15 len[1]=-1; 16 } 17 inline int getfail(int x,int en){ 18 while(s[en]!=s[en-len[x]-1])x=nxt[x]; 19 return x; 20 } 21 inline void insert(int t,int en){ 22 int now=getfail(last,en); 23 if(!ch[now][t]){ 24 int x=++tot; 25 memset(ch[x],0,sizeof ch[x]); 26 len[x]=len[now]+2; 27 int fa=getfail(nxt[now],en); 28 nxt[x]=ch[fa][t]; 29 fa=fro[now]; 30 if(len[x]<=2)fro[x]=0; 31 else{ 32 while(s[en]!=s[en-len[fa]-1]||(len[fa]+2)*2>len[x]) 33 fa=nxt[fa]; 34 fro[x]=ch[fa][t]; 35 } 36 if(len[x]&1||len[x]<=2)f[x]=len[x]; 37 else f[x]=min(f[now]+1,len[x]/2-len[fro[x]]+f[fro[x]]+1); 38 ans=min(ans,n-len[x]+f[x]); 39 ch[now][t]=x; 40 } 41 last=ch[now][t]; 42 } 43 int hash(char x){ 44 if(x=='A')return 0; 45 if(x=='T')return 1; 46 if(x=='C')return 2; 47 return 3; 48 } 49 void work(){ 50 init(); 51 scanf("%s",s); 52 n=strlen(s); 53 for(int i=0;i<n;i++) 54 insert(hash(s[i]),i); 55 printf("%d ",ans); 56 } 57 int main(){ 58 scanf("%d",&T); 59 while(T--)work(); 60 return 0; 61 }