一、题目
二、解法
可以发现答案的构成一定是这个样子的:一个回文串,其它暴力填,因为构造回文一定比暴力填要优。
设 d p [ i ] dp[i] dp[i]为达到自动机上 i i i状态所需要的步数,最终的答案是求 n + d p [ i ] − l e n [ i ] n+dp[i]-len[i] n+dp[i]−len[i]最小,为了保证更新顺序,我们用队列来更新,更新方法如下:
- 从父节点跳转移而来,也就是 d p [ t o ] = d p [ t ] + 1 dp[to]=dp[t]+1 dp[to]=dp[t]+1,因为我们可以再回文翻倍之前加入我们需要的字符,所以只需要多花费 1 1 1的步数。
- 我们先处理出 t r a n s trans trans指针,即不大于原长度 1 2 \frac{1}{2} 21的最长回文后缀,当前回文串可以由 t r a n s trans trans回文翻倍过来,我们再把不够的部分暴力填上,所以这样更新: d p [ t o ] = d p [ t r a n s ] + 1 + l e n [ t o ] / 2 − l e n [ t r a n s ] dp[to]=dp[trans]+1+len[to]/2-len[trans] dp[to]=dp[trans]+1+len[to]/2−len[trans]
然后 t r a n s trans trans的构造方法及一些细节都不说了,看代码把qwq。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int M = 500005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int T,n,ans;char s[M];
struct Pam
{
int n,last,cnt,fail[M],len[M],tr[M],ch[M][4],dp[M];
void clear()
{
fail[0]=1;len[1]=-1;
cnt=1;last=n=0;
}
int get_fail(int x)
{
while(s[n-len[x]-1]^s[n])
x=fail[x];
return x;
}
void ins()
{
n++;
int p=get_fail(last),c=s[n]-'A';
if(!ch[p][c])
{
len[++cnt]=len[p]+2;
int tmp=get_fail(fail[p]);
fail[cnt]=ch[tmp][c];
ch[p][c]=cnt;
if(len[cnt]<=2) tr[cnt]=fail[cnt];
else
{
tmp=tr[p];
while(s[n-len[tmp]-1]^s[n] || ((len[tmp]+2)<<1)>len[cnt])
tmp=fail[tmp];
tr[cnt]=ch[tmp][c];
}
}
last=ch[p][c];
}
void sol()
{
int ans=n;
queue<int> q;
q.push(0);dp[0]=1;
for(int i=2;i<=cnt;i++) dp[i]=len[i];
//需要赋值是因为1为根的状态不会被访问,但需要用到
while(!q.empty())
{
int t=q.front();
q.pop();//用队列更新qwq
for(int i=0;i<4;i++)
{
int to=ch[t][i];
if(!to) continue;
dp[to]=dp[t]+1;
dp[to]=min(dp[to],dp[tr[to]]+1+len[to]/2-len[tr[to]]);
ans=min(ans,dp[to]+n-len[to]);
q.push(to);
}
}
printf("%d\n",ans);
}
}A;
int main()
{
T=read();
while(T--)
{
scanf("%s",s+1);
n=strlen(s+1);
for(int i=0;i<=n+1;i++)
for(int j=0;j<4;j++)
A.ch[i][j]=0;//不能memset,暴力mem见祖宗
A.clear();
for(int i=1;i<=n;i++)
{
if(s[i]=='C') s[i]='B';//离散一下qwq
if(s[i]=='G') s[i]='C';
if(s[i]=='T') s[i]='D';
A.ins();
}
A.sol();
}
}