题目大意:

你要用ATGC四个字母用两种操作拼出给定的串:

  1. 将其中一个字符放在已有串开头或者结尾
  2. 将已有串复制,然后reverse,再接在已有串的头部或者尾部

    一开始已有串为空。求最少操作次数。

    len<=100000

题解:

我们一看 ! 这道题跟回文自动机没有半毛钱关系啊 !!

仔细分析一下第二个操作,我们发现这个操作过后实际上就产生了一个大回文串

所以我们可以考虑如何在回文自动机上搞

一开始想歪了,一直倒着想:如何把给定字符串消掉,然后一直没有想出来


其实这道题应该正着想

设\(f_i\)表示达到回文自动机中的第\(i\)个节点所需要的最小操作.

那么我们有:

对于所有的通过添加一个字符可以转移到\(i\)的\(f_j\)

有\(f_i = min\{f_j + 1\}\)即在得到\(j\)倍增之前添加一个字符于是转移到i

注意 : 最优化下最后一步一定是倍增

我们还有\(f_i = min\{ \frac{len_i}{2} + f_{fail_i} - len_{fail_i} + 1\}\)

就是考虑这个串由所有回文后缀转移过来.

但是这样转移其实是\(O(n^2)\)的,我们应到考虑优化

其实我们发现:如果跳fail指针,那么\(f_{fail_i}\)会变小,但是相应的另一部分会变大

由反证法可得,一定不会出现决策时选择\(fail_i\)比\(fail_{fail_i}\)更优的情况

所以我们只需要考虑取到的第一个可行决策即可.

但是这样还是不够:可行决策的两个条件:

  • s[len-T[x].len-1] == s[len]
  • (T[x].len+2)*2 <= T[cur].len

找到第一个可行决策的时间过长,依然会TLE

所以我们考虑记录一下每个节点的第一个可行决策

在找最优决策的时候,我们跳转last的可行决策,然后跳fail继续查找即可

不难发现这样一定是对的:

证明:

我们设当前新建状态为\(cur\)那么当我们利用第二个dp方程转移时一定有\(T[cur].len < T[last].len\)

所以对于\(last\)不成立的状态即\((T[x].len+2)*2 > T[last].len\)

一定也有\((T[x].len+2)*2 > T[last].len\)

故一定可以直接从\(last\)的可行决策点向前取.

所以我们在正常地找出第一个可以拓展成目前最长回文后缀的状态

对着这个状态的决策点一直向前跳即可.

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 100010;
inline int idx(char ch){
if(ch == 'A') return 0;
if(ch == 'T') return 1;
if(ch == 'C') return 2;
if(ch == 'G') return 3;
return 0;
}
struct Node{
int nx[4];
int fail,len,p;
void clear(){
nx[0] = nx[1] = nx[2] = nx[3] = 0;
fail = len = p = 0;
}
}T[maxn];
int last,nodecnt,len,s[maxn];
inline void init(){
last = nodecnt = 0;
T[0].clear();T[1].clear();
T[++nodecnt].len = -1;
T[0].fail = 1;
s[len=0] = -1;
}
inline void insert(int c){
s[++len] = c;int cur,p,x;
for(p = last;s[len-T[p].len-1] != s[len];p = T[p].fail);
if(T[p].nx[c] == 0){
T[nodecnt+1].clear();T[cur = ++nodecnt].len = T[p].len + 2;
for(x = T[p].fail;s[len-T[x].len-1] != s[len];x = T[x].fail);
T[cur].fail = T[x].nx[c];
T[p].nx[c] = cur;
if(T[cur].len <= 2) T[cur].p = T[cur].fail;
else{
for(x = T[p].p;s[len-T[x].len-1] != s[len] || (T[x].len+2)*2 > T[cur].len;x = T[x].fail);
T[cur].p = T[x].nx[c];
}
}last = T[p].nx[c];
}
char str[maxn];
int q[maxn],l,r,f[maxn];
int main(){
int n;read(n);
while(n--){
init();scanf("%s",str);
int len = strlen(str);
for(int i=0;i<len;++i) insert(idx(str[i]));
for(int i=2;i<=nodecnt;++i){
if(T[i].len&1) f[i] = T[i].len;
} l = 0;r = -1;q[++r] = 0;f[0] = 1;
int ans = len;
while(l <= r){
int u = q[l++],v;
for(int i=0;i<4;++i){
v = T[u].nx[i];
if(v == 0) continue;
f[v] = min(f[u] + 1,T[v].len/2 + f[T[v].p] - T[T[v].p].len + 1);
ans = min(ans,f[v] + (len - T[v].len));
q[++r] = v;
}
}printf("%d\n",ans);
}
getchar();getchar();
return 0;
}

bzoj 4044: Virus synthesis 回文自动机的更多相关文章

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

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

  2. BZOJ 4044 Virus synthesis (回文自动机+dp)

    题目大意: 你可以在一个串的开头或者末尾加入一个字符,或者把当前整个串$reverse$,然后接在前面或者后面,求达到目标串需要的最少操作次数 对目标串建出$PAM$ 定义$dp[x]$表示当前在回文 ...

  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. bzoj 2160: 拉拉队排练 回文自动机

    题目: Description 艾利斯顿商学院篮球队要参加一年一度的市篮球比赛了.拉拉队是篮球比赛的一个看点,好的拉拉队往往能帮助球队增加士气,赢得最终的比赛.所以作为拉拉队队长的楚雨荨同学知道,帮助 ...

  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. js实现table内 某列的内容进行即时筛选

    往往有些时候,我们把数据从数据库读取出来,显示到table里面,而此时来了个新需求,要在一个搜索框内输入关键字,表格的内容进行即时的筛选. 而即时触发进行数据库的查询,再回调显示,就显得慢,拖累服务器 ...

  2. spring+struts1

    概括及介绍: 集成原理:在Action 中获得BeanFactory,通过BeanFactory取得业务逻辑对象 本例采用:JDK1.8,tomcat7.0.9  技术点:spring与strut1集 ...

  3. Struts2+hibernate+spring 配置事物

    今天自信看了看hibernate的事物配置问题,转载了其他人的日志,仅用来学习. struts+hibernate+spring事务配置 (2009-01-14 21:49:47) 转载▼ 标签: i ...

  4. [转]为 windows cmd 设置代理

    为 windows cmd 设置代理 转自:http://blog.csdn.net/lovelyelfpop/article/details/69586366 通过cmd命令行执行某些命令,如果这些 ...

  5. Servlet学习笔记【1】--- 背景和基础知识(CGI、Web服务器发展史、Servlet简介、任务、继承结构)

    本文主要讲Servlet的基础知识和背景知识. 1 CGI简介 CGI(Common Gateway Interface 公共网关接口)是WWW技术中最重要的技术之一,有着不可替代的重要地位.CGI是 ...

  6. ElasticSearch(十八)初识分词器

    1.什么是分词器 作用:切分词语,normalization(提升recall召回率),如给你一段句子,然后将这段句子拆分成一个一个的单个的单词,同时对每个单词进行normalization(时态转换 ...

  7. HDU 4513 吉哥系列故事――完美队形II(Manacher)

    题目链接:cid=70325#problem/V">[kuangbin带你飞]专题十六 KMP & 扩展KMP & Manacher V - 吉哥系列故事――完美队形I ...

  8. (转)linux访问windows共享文件夹的两种方法

    有时需要在linux下访问window的共享文件,可以使用mount挂载或使用samba连接. 1,mount挂载 $ mkdir windows 将共享文件夹挂载到windows文件夹: mount ...

  9. python 学习2:生成器,迭代器,装饰器

    1.生成器 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万  个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那 ...

  10. 用cocos2d-html5做的消除类游戏《英雄爱消除》(4)——游戏结束

    游戏结束界面: 在前面几个教程中,这个界面的创作所需要的知识点基本我们都讲过了,这里就说下用户数据的缓存吧,也是先来看下源码 /** * Power by html5中文网(html5china.co ...