题目传送门

  需要高级权限的传送门

题目大意

  要求用两种操作拼出一个长度为$n$的只包含'A','T','G','C'的字符串

  1. 在当前字符串头或字符串结尾添加一个字符
  2. 将当前字符串复制,将复制的串翻转,接在当前字符串末尾或者当前字符串头部、

  问最少的操作次数。

  考虑正常的动态规划时怎么做的。用$f[i][j]$表示拼出给定串的$[l, r]$的最少用的步数。转移显然。

  然而它的时间爆了。空间也爆了。

  仔细观察发现,翻转完最后一个偶回文串后,两端的字符只能暴力插入。

  但是一个串的本质不同的回文串的总数是$O(n)$的级别。因此可以考虑在回文树上动态规划。

  然后用$f[x] + n - len(x)$去更新答案。

  转移显然要分奇偶性讨论。

  1. 如果当前的回文串是奇回文串,那么通过它的最长回文后缀转移,然后暴力补上缺字符,即$f[x] = f[fail[x]] + len(x) - len(fail[x])$。
  2. 如果当前的回文串是偶回文串,那么继续讨论
    • 可以通过它的长度不超过它的一半的最长回文后缀补上一半的残缺字符,然后翻转转移。
    • 如果通过它去掉两端字符的偶回文串在翻转之前再补上一个字符转移。即$f[y] + 1$

  另外说一句,奇回文串的$f[x]$设为$len(x)$也没有任何影响。

  求$half$的做法可以参考NOI某年的动物园。

Code

 /**
* bzoj
* Problem#4044
* Accepted
* Time: 3264ms
* Memory: 4512k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; int cti(char x) {
if (x == 'A') return ;
if (x == 'G') return ;
if (x == 'T') return ;
return ;
} const int N = 1e5 + ; typedef class TrieNode {
public:
int len, f;
TrieNode* ch[];
TrieNode *fail, *half;
}TrieNode; TrieNode pool[N];
TrieNode* top; TrieNode* newnode(int len) {
top->len = len;
memset(top->ch, , sizeof(top->ch));
return top++;
} typedef class PalindromeTree {
public:
char *str;
TrieNode *even, *odd;
TrieNode *last; PalindromeTree() { }
PalindromeTree(char *str):str(str) {
top = pool;
odd = newnode(-);
even = newnode();
odd->fail = odd, even->fail = odd, last = odd;
odd->half = odd, even->half = odd;
} TrieNode* extend(TrieNode* p, int pos) {
while (str[pos] != str[pos - p->len - ]) p = p->fail;
return p;
} void build() {
for (int i = ; str[i]; i++) {
int c = cti(str[i]);
last = extend(last, i);
if (!last->ch[c]) {
TrieNode* pn = newnode(last->len + );
pn->fail = extend(last->fail, i)->ch[c];
if (!pn->fail)
pn->fail = even;
TrieNode* f = last->half;
f = extend(f, i)->ch[c];
if (!f)
f = even;
while (f->len * > pn->len)
f = f->fail;
pn->half = f;
last->ch[c] = pn;
}
last = last->ch[c];
}
} void dp() {
for (TrieNode* p = pool; p < top; p++)
p->f = p->len;
for (TrieNode* p = pool + ; p < top; p++)
if (p->len & )
p->f = p->fail->f + (p->len - p->fail->len);
else {
p->f = min(p->f, p->half->f + ((p->len >> ) - p->half->len) + );
for (int c = ; c < ; c++)
if (p->ch[c])
p->ch[c]->f = min(p->ch[c]->f, p->f + );
}
}
}PalindromeTree; int T;
char str[N];
PalindromeTree pam; inline void init() {
scanf("%s", str + );
} inline void solve() {
pam = PalindromeTree(str);
pam.build();
pam.dp();
int res = , len = strlen(str + );
// for (TrieNode* p = pool; p < top; p++)
// cerr << p - pool << " " << p->fail - pool << " " << p->half - pool << " " << p->len << endl;
for (TrieNode* p = pool; p < top; p++)
res = min(res, len - p->len + p->f);
printf("%d\n", res);
} int main() {
scanf("%d", &T);
while (T--) {
init();
solve();
}
return ;
}

bzoj 4044 Virus synthesis - 回文自动机 - 动态规划的更多相关文章

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

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

  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. Codeforces Gym100543G Virus synthesis 字符串 回文自动机 动态规划

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF-100543G.html 题目传送门 - CF-Gym100543G 题意 你可以对一个字符串进行以下两种操 ...

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

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

随机推荐

  1. React对比Vue(02 绑定属性,图片引入,数组循环等对比)

    import React, { Component } from 'react'; import girl from '../assets/images/1.jpg' //这个是全局的不要this.s ...

  2. cocos2d JS-(JavaScript) 类型检测与判断

    //检测类型 var str = "Hello World"; if (typeof str=="string") {//使用typeof来判断对象类型的一个例 ...

  3. Uncaught DOMException: Blocked a frame with origin "http://localhost

    ajaxFileUpload上传时报错 :Uncaught DOMException: Blocked a frame with origin "http://localhost..... ...

  4. CSU 1849 Comparing answers(数学矩阵)

    Comparing answers 离散数学真的要好好学啊:一个邻接矩阵(这个矩阵一定是n×n的方阵,n是图的节点个数),表示的是从i到j有几条通路的时候,矩阵的1次方就代表从从i到j长度为1的路径通 ...

  5. C# Control.Invoke匿名委托

    if (txbValue.InvokeRequired) txbValue.Invoke(new MethodInvoker(delegate() {                          ...

  6. c# Mongodb批量更新

    public void Put(List<OnlineItem> datas)         {             try             {                ...

  7. Git branch 分支与合并分支

    Git branch 分支 查看当前有哪些branch bixiaopeng@bixiaopengtekiMacBook-Pro xmrobotium$ git branch * master 新建一 ...

  8. sitecore系统教程之媒体库

    您可以管理媒体库中的所有媒体项目,例如要嵌入网页的图像或供访问者下载的图像.媒体库包含所有媒体项目,例如图像,文档,视频和音频文件. 在媒体库中,您可以: 将所有媒体文件保存在一个位置,并将其组织在与 ...

  9. linux centos重置mysql密码教程

    第一步 查看确定安装了mysql # rpm -qa|grep -i mysql 执行效果如下 第二步 重启mysql: # /etc/init.d/mysqld 截图如下 因为我已经开了,所以用re ...

  10. python SQLite说一点点, python使用数据库需要注意的几点

    SQLite是一种嵌入式数据库,它的数据库就是一个文件.由于SQLite本身是C写的,而且体积很小,所以,经常被集成到各种应用程序中,甚至在iOS和Android的App中都可以集成. Python就 ...