题目大意:

你可以在一个串的开头或者末尾加入一个字符,或者把当前整个串$reverse$,然后接在前面或者后面,求达到目标串需要的最少操作次数

对目标串建出$PAM$

定义$dp[x]$表示当前在回文树的x节点,拼凑出这个节点表示的回文串所需要的最小操作次数

$fa_{x}$表示沿着树边指向它的父亲,$pre_{x}$表示它的$fail$指针

如果它是奇回文串,一定不能被翻转得到,所以开头结尾各需要加上一个字符,$dp[x]=dp[fa_{x}]+2$

如果它是偶回文串,可以被翻转得到

1.要么是在上次翻转之前先添加一个字符,再翻转得到,$dp[x]=dp[fa_{x}]+1$

2.要么是在这次进行翻转,需要保证被翻转的串长度不大于$dep[x]/2$

可以在回文树上倍增跳$pre$,找到$x$的一个长度不大于$dep[x]/2$的回文后缀所在节点$y$

只需要找后缀的情况即可,其他的情况会被合并到情况一里

剩下的部分也要被暴力地填上,那么$dp[x]=dp[y]+dep[x]/2-dep[y]+1$

 #include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 100100
#define S1 (N1<<1)
#define ll long long
#define uint unsigned int
#define rint register int
#define dd double
#define il inline
#define inf 0x3f3f3f3f
using namespace std; int len,T;
inline int idx(char x)
{
if(x=='A') return ;
if(x=='C') return ;
if(x=='G') return ;
if(x=='T') return ;
}
char str[N1];
int lg[N1];
namespace PAM{
int trs[N1][],pre[N1],dep[N1],fa[N1],dp[N1],la,tot;
int ff[N1][];
void init()
{
tot++;
memset(trs,,tot**),memset(pre,,tot*);
memset(ff,,tot**),memset(fa,,tot*);
memset(dp,,tot*),memset(dep,,tot*);
la=tot=,dep[]=-;pre[]=pre[]=;
}
int chk(char *str,int i,int p){return str[i-dep[p]-]!=str[i]?:;}
void insert(char *str,int i)
{
int p=la,np,fp,c=idx(str[i]);
while(chk(str,i,p)) p=pre[p];
if(!trs[p][c])
{
np=++tot;
dep[np]=dep[p]+;
fp=pre[p];
while(chk(str,i,fp)) fp=pre[fp];
pre[np]=trs[fp][c];
trs[p][c]=np;
fa[np]=p;
}
la=trs[p][c];
}
int solve()
{
int i,j,x,ans=len,de;
ff[][]=ff[][]=ff[][]=ff[][]=;
for(i=;i<=tot;i++) ff[i][]=i,ff[i][]=pre[i];
for(j=;j<=;j++)
for(i=;i<=tot;i++)
ff[i][j]=ff[ ff[i][j-] ][j-];
dp[]=,dp[]=-;
for(i=;i<=tot;i++)
{
x=i;
dp[i]=dp[fa[i]]+((dep[i]&)?:);
if((dep[i]&)) continue;
for(j=lg[dep[i]];j>=;j--)
if(dep[ff[x][j]]>=dep[i]/) x=ff[x][j];
if(dep[x]>dep[i]/) x=pre[x];
dp[i]=min(dp[i],dp[x]++dep[i]/-dep[x]);
ans=min(ans,len-dep[i]+dp[i]);
}
return ans;
}
}; int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%s",str+);
len=strlen(str+);
int i;
for(lg[]=,i=;i<=len;i++) lg[i]=lg[i>>]+;
PAM::init();
for(i=;i<=len;i++) PAM::insert(str,i);
printf("%d\n",PAM::solve());
}
return ;
}

最新文章

  1. 使用VC6.0创建和运行C程序的方法
  2. html css 编写规范
  3. js 监听窗口变化
  4. Jenkins初探
  5. flask log
  6. NOIP总结
  7. ADO.NET(很精彩全面)
  8. Shell常用操作
  9. 将垃圾送入无底洞,顺便整理dev知识
  10. c/c++ 重载 数组 操作符[] operator[ is ambiguous, as 0 also mean a null pointer of const char* type.
  11. 作品第一课----改变DIV样式属性
  12. 获取IMEI码
  13. 解决Shockwave flash在chrome浏览器上崩溃的问题
  14. Android开发周报:反编译对抗研究、动手制作智能镜子
  15. FFmpeg源代码简单分析:avio_open2()
  16. PYTHON-模块定义 搜索路径
  17. POJ 1873 The Fortified Forest(凸包)题解
  18. 【JavaScript】浅析JavaScript中arguments对象的使用
  19. C++头文件&lt;bits/stdc++.h&gt;
  20. 3.CentOS的一些小笔记

热门文章

  1. UVA-11806 Cheerleaders 计数问题 容斥定理
  2. pycharm 永久激活 序列码 破解版
  3. JavaScript 事件对内存和性能的影响
  4. [Beginning SharePoint Designer 2010]Chapter 3 分析SharePoint页面
  5. 定时任务为什么不用Timer
  6. Android 四大组件学习之ContentProvider三
  7. 非Qt工程使用Qt的信号槽机制
  8. 0x02 枚举、模拟、递推
  9. Redis学习笔记(一) 初识 Redis
  10. centos7 usually use