【BZOJ】4044: [Cerc2014] Virus synthesis-迴文自動機
阿新 • • 發佈:2019-01-03
傳送門:bzoj4044
題解
操作可以生成一個長度為偶的迴文串。
對於長度 的迴文串,用 來構造相比直接加會使得操作次數減少, 時也不虧。那麼問題就轉化成了找到一個極大的偶迴文串來優化答案。
在這道題,完全不需要考慮到奇迴文串,因為若其內部不包含偶迴文,就不能執行 ,若其內部包含偶迴文,也只需要考慮這個內部的偶迴文再在外部插入單個字元即可。
設偶迴文
的長度為
,最少構造操作次數為
。
設字串總長為
,則
構造迴文自動機,遞推得到 :
設偶迴文串
首尾分別去掉一個字元得到
,則
(末尾填一個字元後
)
設長度
的最長的
的字尾偶迴文串為
,則
注意不能每次暴力跳父邊找 ,需要記錄 後向下找,才能保證複雜度是線性的(奇偶迴文串都要記錄 )
程式碼
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100;
int tk,n,p,ans,w[N],las[N];
int len[N],f[N],ch[N][26],cnt;
char s[N];
inline int new_node(int x)
{len[cnt]=x;ch[cnt][0]=ch[cnt][2]=ch[cnt][6]=ch[cnt][19]=0;f[cnt]=0;return cnt++;}
inline int get_fail(int p,int m)
{for(;s[m-len[p]]!=s[m+1];p=f[p]);return p;}
inline void ins(int alp,int m)
{
p=get_fail(p,m);
if(!ch[p][alp]){
int i,cur=new_node(len[p]+2);
if(!(len[p]&1)) w[cur]=min(len[cur],w[p]+1);
f[cur]=ch[get_fail(f[p],m)][alp];
ch[p][alp]=cur;
if(len[cur]<=2) las[cur]=f[cur];
else{
for(i=las[p];s[m-len[i]]!=s[m+1] || (((len[i]+2)<<1)>len[cur]);i=f[i]);
las[cur]=ch[i][alp];if(!(len[cur]&1)){
for(i=las[cur];i>1 && (len[i]&1);i=f[i]);
if(i>1) w[cur]=min(w[cur],w[i]+len[cur]/2-len[i]+1);
}
}
}
p=ch[p][alp];
}
inline void sol()
{
int i,j,k;
scanf("%s",s+1);w[0]=1;n=strlen(s+1);cnt=0;
f[new_node(0)]=new_node(-1);
p=0;ans=n;for(i=1;i<=n;++i) ins(s[i]-'A',i-1);
for(i=2;i<cnt;++i) if(!(len[i]&1)) ans=min(ans,w[i]+n-len[i]);
printf("%d\n",ans);
}
int main(){
for(scanf("%d",&tk);tk;--tk) sol();
return 0;
}