解析
自己对PAM的理解不够深刻。
最优方案必然是先选择一个偶回文串,递归构造出它的一半。花一步逆序,然后暴力解决剩下的。
这似乎已经依稀出现了某种dp的思路。
考虑如何更好的转移。设计
t
r
a
n
s
x
trans_x
transx 表示长度不超过
x
x
x 一半的最长回文后缀,可以用类似 fail
指针的方法获得。
那么dp就分别尝试从后缀树上和 trans
转移即可。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
inline ll read(){
ll x(0),f(1);char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
const int N=3e5+100;
const int mod=19930726;
int n;
int lst=1,tot=1;
int len[N],fa[N],tr[N][4],dp[N],trans[N],ans;
char s[N];
map<char,int>mp;
inline void init(){
len[0]=0;len[1]=-1;
fa[0]=1;fa[1]=0;
//trans[0]=1;
for(int i=0;i<=tot;i++){
for(int j=0;j<=3;j++) tr[i][j]=0;
}
tot=1;lst=1;ans=n;
return;
}
inline int find(int x,int i){
while(s[i-len[x]-1]!=s[i]) x=fa[x];
return x;
}
inline void ins(int c,int id){
lst=find(lst,id);
if(!tr[lst][c]){
int cur=++tot;
len[cur]=len[lst]+2;
fa[cur]=tr[find(fa[lst],id)][c];
tr[lst][c]=cur;
if(len[cur]<=2) trans[cur]=fa[cur];
else{
int o=trans[lst];
while(s[id-len[o]-1]!=s[id]||len[o]+2>len[cur]/2)
o=fa[o];//printf("%d\n",o);
trans[cur]=tr[o][c];
}
}
lst=tr[lst][c];
return;
}
int q[N],st,ed;
void work(){
scanf(" %s",s+1);n=strlen(s+1);
init();
for(int i=1;i<=n;i++) ins(mp[s[i]],i);
for(int i=2;i<=tot;i++) dp[i]=len[i];
st=1,ed=0;
q[++ed]=0;
while(st<=ed){
int now=q[st++];
ans=min(ans,n-len[now]+dp[now]);
dp[0]=1;
for(int j=0;j<=3;j++){
int to=tr[now][j];
if(!to) continue;
dp[to]=min(dp[now]+1,dp[trans[to]]+len[to]/2-len[trans[to]]+1);
q[++ed]=to;
}
// printf("now=%d len=%d trans=%d dp=%d\n",now,len[now],trans[now],dp[now]);
}
//for(int i=0;i<=tot;i++){
// printf("i=%d A:%d T:%d C:%d G:%d len=%d fa=%d trans=%d dp=%d\n",i,tr[i][0],tr[i][1],tr[i][2],tr[i][3],len[i],fa[i],trans[i],dp[i]);
//}
printf("%d\n",ans);
}
signed main(){
#ifndef ONLINE_JUDGE
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
#endif
mp['A']=0;
mp['T']=1;
mp['C']=2;
mp['G']=3;
int T=read();
while(T--) work();
return 0;
}
/*
1
AAGGGGAAGGGGAA
*/