题目大意:

你可以在一个串的开头或者末尾加入一个字符,或者把当前整个串$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 ;
}

BZOJ 4044 Virus synthesis (回文自动机+dp)的更多相关文章

  1. bzoj 4044: Virus synthesis 回文自动机

    题目大意: 你要用ATGC四个字母用两种操作拼出给定的串: 将其中一个字符放在已有串开头或者结尾 将已有串复制,然后reverse,再接在已有串的头部或者尾部 一开始已有串为空.求最少操作次数. le ...

  2. bzoj 4044 Virus synthesis - 回文自动机 - 动态规划

    题目传送门 需要高级权限的传送门 题目大意 要求用两种操作拼出一个长度为$n$的只包含'A','T','G','C'的字符串 在当前字符串头或字符串结尾添加一个字符 将当前字符串复制,将复制的串翻转, ...

  3. bzoj4044/luoguP4762 [Cerc2014]Virus synthesis(回文自动机+dp)

    bzoj4044/luoguP4762 [Cerc2014]Virus synthesis(回文自动机+dp) bzoj Luogu 你要用ATGC四个字母用两种操作拼出给定的串: 1.将其中一个字符 ...

  4. BZOJ 4044 Luogu P4762 [CERC2014]Virus Synthesis (回文自动机、DP)

    好难啊..根本不会做..基本上是抄Claris... 题目链接: (bzoj)https://www.lydsy.com/JudgeOnline/problem.php?id=4044 (luogu) ...

  5. [BZOJ4044]Virus synthesis 回文自动机的DP

    4044: [Cerc2014] Virus synthesis Time Limit: 20 Sec  Memory Limit: 128 MB Description Viruses are us ...

  6. luogu P4762 [CERC2014]Virus synthesis (回文自动机)

    大意: 初始有一个空串, 操作(1)在开头或末尾添加一个字符. 操作(2)在开头或末尾添加该串的逆串. 求得到串$S$所需最少操作数. 显然最后一定是由某个偶回文通过添加字符得到的, 那么只需要求出所 ...

  7. bzoj2084/luoguP3501 [Poi2010]Antisymmetry(回文自动机+dp)

    bzoj2084/luoguP3501 [Poi2010]Antisymmetry(回文自动机+dp) bzoj Luogu 对于一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一 ...

  8. bzoj 4044: [Cerc2014] Virus synthesis【回文自动机+dp】

    建回文自动机,注意到一个回文串是可以通过一个长度小于等于这个串长度的一半的回文串添上一些字符然后复制得到的,也就是在自动机上向fa走,相当于treedp 每次都走显然会T,记录一个up,指向祖先中最下 ...

  9. [CERC2014]Virus synthesis【回文自动机+DP】

    [CERC2014]Virus synthesis 初始有一个空串,利用下面的操作构造给定串 SS . 1.串开头或末尾加一个字符 2.串开头或末尾加一个该串的逆串 求最小化操作数, \(|S| \l ...

随机推荐

  1. 重置浏览器默认样式 normalize.css

    1 /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ /* Document ========= ...

  2. vue 动态添加路由 require.context()

    之前的写法 'use strict' import Vue from 'vue' import MessageBroadcast from 'page/MessageBroadcast' import ...

  3. 深入理解Java中的锁

    转载:https://www.jianshu.com/p/2eb5ad8da4dc Java中的锁 常见的锁有synchronized.volatile.偏向锁.轻量级锁.重量级锁 1.synchro ...

  4. 怎样改动 VC6.0 4.0 2010 打印预览界面上的文字

    前言:尽管早已下决心不再碰微软的东西,但手头的项目还得须要维护. 遇到问题还能解决. 问题由来: 之前的软件开发是基于中文环境开发的,建立项目的时候,选择了中文,为了方便客户使用.我们使用了静态编译的 ...

  5. Python学习笔记-小记

    1.字符串string 推断一个字符(char)是数字还是字母 str.isalpha() #推断是否为字母 str.isdigit() #推断是否为数字 推断一个字符串是否为空 if not str ...

  6. iOS 使用脚本自动化复制target

    有些项目成熟以后,就会有需求自动化配置生成一个全新的项目,不需要再让开发人员手动修改工程文件,将配置化工作直接移交给运维或者配置团队去做 其实按照普通的做法,无非就是在xcode里将目标target ...

  7. kettle 使用excel模板导出数据

    通过excel进行高速开发报表: 建设思路: 1.首先制订相关的execl模板. 2.通过etl工具(kettle)能够高速的 将数据库中的数据按excel模板导出成新的excel就可以. 当中ket ...

  8. c13--数组

    // // main.c // 进制查表法 // // Created by xiaomage on 15/6/10. // Copyright (c) 2015年 xiaomage. All rig ...

  9. Android::开机自启动C程序【转】

    本文转载自:http://blog.csdn.net/Kaiwii/article/details/7681736 之前一篇博文介绍了shell脚本文件的开机启动,地址是http://blog.chi ...

  10. JavaScript学习笔记——对象的创建

    对象是JavaScript基本数据类型,在JavaScript中除了Undefined.Null.布尔型(ture.false).字符串和数字之外,其他的都属于对象. 在JavaScript中,一个对 ...