[CERC2014] Virus synthesis
程序员文章站
2023-04-05 17:12:04
设f[i]为形成极长回文串i的最小操作数。答案为min f[i]+n len[i]。 在不形成偶回文的情况下形成奇回文的最小操作数为该串长度。可以不考虑(但ans赋为len)。 正确性基于: 1)奇、偶回文嵌套形成最终的偶回文一定可以转化为由在不形成奇回文的情况下形成偶回文。 2)奇、偶回文嵌套形成 ......
设f[i]为形成极长回文串i的最小操作数。答案为min f[i]+n-len[i]。
在不形成偶回文的情况下形成奇回文的最小操作数为该串长度。可以不考虑(但ans赋为len)。
正确性基于:
1)奇、偶回文嵌套形成最终的偶回文一定可以转化为由在不形成奇回文的情况下形成偶回文。
2)奇、偶回文嵌套形成最终的奇回文并不需要讨论。
也不知道理解对没有。。。
所以,以下的回文串皆代指偶回文。
转移1:f[i]=f[j]+1 | 在极长回文串j前后补上一对相同字符可得到i。
举例:
aabbaa : a aa aab aabbaa
caabbaac: a aa aab caab caabbaac
统一化:f[偶根]=1 => f["aa"]=2
转移2:f[i]=min f[j]+1+len[i]/2-len[j] | j=tmp[i].
举例:
abba : a ab abba
abbaccabba: abba abbac abbaccabba
#include <bits/stdc++.h> using namespace std; const int n=3e5+10; map<char,int> tr={ {'a',0},{'g',1},{'c',2},{'t',3} }; struct pam_ { char *str; int last,size; int tmp[n],len[n],fail[n],ch[n][26]; int getfail(int x,int n) { while(str[n]!=str[n-len[x]-1]) x=fail[x]; return x; } void build(char *bstr) { str=bstr; str[0]=-1; len[1]=-1; fail[0]=1; last=0; size=1; memset(ch[0],0,sizeof ch[0]); memset(ch[1],0,sizeof ch[1]); for(int i=1; str[i]; ++i) { int c=tr[str[i]]; int p=getfail(last,i); if(!ch[p][c]) { int q=++size; memset(ch[q],0,sizeof ch[q]); len[q]=len[p]+2; fail[q]=ch[getfail(fail[p],i)][c]; ch[p][c]=q; if(len[q]<=2) tmp[q]=fail[q]; else { int x=tmp[p]; while(str[i]!=str[i-len[x]-1]||(len[x]+2)*2>len[q]) x=fail[x]; tmp[q]=ch[x][c]; } } last=ch[p][c]; } } int calc() { static int que[n]; static int f[n]; int n,ans,hd,tl; n=ans=strlen(str+1); que[hd=0,tl=1]=0; for(int i=2; i<=size; ++i) { f[i]=len[i]; } f[0]=1,f[1]=0; while(hd<tl) { int x=que[++hd]; for(int i=0; i<4; ++i) { int y=ch[x][i]; if(!y) continue; f[y]=f[x]+1; que[++tl]=y; f[y]=min(f[y],f[tmp[y]]+1+len[y]/2-len[tmp[y]]); ans=min(ans,f[y]+n-len[y]); } } return ans; } } pam; int main() { int t; scanf("%d",&t); static char str[n]; while(t--) { scanf("%s",str+1); pam.build(str); // puts("built"); printf("%d\n",pam.calc()); } return 0; }
上一篇: PHP实现的简易版图片相似度比较