题目传送门

  需要高级权限的传送门

题目大意

  要求用两种操作拼出一个长度为$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. vue+element-ui中的表单验证(电话等等)

    1. 2. 3. ============================================================上代码============================ ...

  2. cocos2dx 3.x(for 循环让精灵从中间往上下两边排列)

    最近很多游戏都喜欢房卡类的游戏,就是创建房间时(),选择玩法与规则,今天耗费2小时处理这个数学问题:例如选择规则两条,则背景框中间显示两条规则,若选择三条,则背景框中间显示三条规则与玩法,依次从中间往 ...

  3. Spring+SpringMVC+MyBatis整合应用

    1)搭建Spring,SpringMVC和MyBatis环境 创建一个web工程 添加MyBatis相关环境 引入数据库驱动包和DBCP连接池开发包 引入MyBatis开发包 添加Spring,Spr ...

  4. 新节点在线加入PXC

    环境 192.168.139.151 新增节点 192.168.139.148-150 集群节点 192.168.139.151 已经安装好PXC软件 计划: 选用192.168.139.150 节点 ...

  5. MYSQL5.6.X 非在线安装版(解压版)安装过程

    一.卸载以前旧版本(本人5.5版本) 1.关闭MySQL服务 以管理员身份运行cmd,执行以下命令: net stop mysql 或者右键我的电脑,在管理——服务——停止MySQL 2.卸载MySQ ...

  6. Python 字典(Dictionary) values()方法

    描述 Python 字典(Dictionary) values() 函数以列表返回字典中的所有值. 语法 values()方法语法: dict.values() 参数 NA. 返回值 返回字典中的所有 ...

  7. Nginx配置基础-location

    location表达式类型 ~ 表示执行一个正则匹配,区分大小写~* 表示执行一个正则匹配,不区分大小写^~ 表示普通字符匹配.使用前缀匹配.如果匹配成功,则不再匹配其他location.= 进行普通 ...

  8. PyCharm2017破解步骤

    前段时间买了一套python的学习视频,附带一个Pycharm的安装包和注册码,现在注册码被JetBrains封杀了,不得已在网上找了一下破解的教程,在这里记录一下: 先找到破解补丁无需使用注册码,下 ...

  9. 初探AngularJs框架(二)

    一.创建Components组件 直接使用AngularCLI即可很方便的创建component组件,使用如下指令: ng g component components/news 这样就会在compo ...

  10. Linux服务器---邮件服务器dovecot

    安装dovecot Dovecot是CentOS系统中著名的POP3/IMAP服务器实现.POP3/IMAP是从邮件服务器中读取邮件时使用的协议,POP3将邮件全部从服务器中拖取下来:IMAP则每次从 ...