原文链接https://www.cnblogs.com/zhouzhendong/p/CF-100543G.html

题目传送门 - CF-Gym100543G

题意

  你可以对一个字符串进行以下两种操作:

  1.  在其头或者尾部加入一个新字符

  2.  翻转当前字符串,并把他拼接在当前字符串的前面或者后面

  给你 T 组询问,每组询问一个字符串,问你至少要多少次操作才能生成这个串。

  字符集 = ${'A','C','G','T'}$ ,字符串串长 $\leq 100000$

题解

  第一次写回文自动机。现学现用。

  写完调不出样例。网上看了看 Claris 的代码。研究了一下,继续调。样例是过了,一交 wa 。思索之后,重新打开 Claris 的博客。然后把代码改的和他差不多了 QAQ

  做法:

  我们先建一棵 PAM 。

  然后考虑在 PAM 上面 DP 。

  令当前串在 PAM 上面的状态为 $x$ 。

  考虑长度为 偶数 的回文串,分两种情况:

    折半,令节点 $y$ 为长度小于等于 $len_x$ 的一般的最长回文子串,则 $ dp_x=\min(dp_x,dp_y+(\cfrac {len_x}{2} - len_y) + 1) $

    删除两侧字符,令节点 $y$ 为当前回文串删除两侧节点得到,那么由于我们可以先折半再删除,所以 $dp_x=min(dp_x,dp_y+1)$ 。

  考虑长度为 奇数 的回文串,令 $dp_i=len_i$,分两种情况说明他是对的:

    该串下一步暴力填充至完成全串: 则选择该串不如直接选择偶串,故令 $dp_i=len_i$ 不亏。

    该串由偶串折半而来,那么由于在折半前有偶串的“删除两侧字符”这个转移,故不需要在奇串的转移中加入删除左侧或者右侧字符的转移 。

  具体做法见代码。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=100005;
struct PAM{
static const int C=4;
int Next[N][C],fail[N],len[N],s[N],last,n,p;
int Half[N];
int newnode(int L){
memset(Next[p],0,sizeof Next[p]);
len[p]=L;
return p++;
}
void init(){
p=last=n=Half[0]=Half[1]=0;
newnode(0),newnode(-1);
s[0]=-1,fail[0]=1,fail[1]=0;
}
int getfail(int x){
while (s[n-len[x]-1]!=s[n])
x=fail[x];
return x;
}
void add(int c){
s[++n]=c;
int x=getfail(last);
if (!Next[x][c]){
int y=newnode(len[x]+2);
fail[y]=Next[getfail(fail[x])][c];
if (len[y]<=2)
Half[y]=fail[y];
else {
int z=Half[x];
while (s[n-len[z]-1]!=s[n]||(len[z]+2)*2>len[y])
z=fail[z];
Half[y]=Next[z][c];
}
Next[x][c]=y;
}
last=Next[x][c];
}
}pam;
int T,n,Turn[300],dp[N];
int q[N],head,tail;
char s[N];
int main(){
Turn['A']=0,Turn['C']=1,Turn['G']=2,Turn['T']=3;
scanf("%d",&T);
while (T--){
scanf("%s",s);
n=strlen(s);
pam.init();
for (int i=0;i<n;i++)
pam.add(Turn[s[i]]);
// 考虑长度为 偶数 的串,分两种情况:
// 折半
// 删除两侧字符
// 考虑长度为 奇数 的串,分两种情况:
// 该串下一步暴力填充至完成全串: 则选择该串不如直接选择偶串,故令 dp[i]=len[i]
// 该串由偶串折半而来,那么由于在折半前有偶串的“删除两侧字符”这个转移,故不需要在奇串的转移中加入删除左侧或者右侧字符的转移
for (int i=2;i<pam.p;i++)
if (pam.len[i]&1)
dp[i]=pam.len[i];
int ans=n;
head=tail=0,dp[0]=1,q[++tail]=0;
while (head<tail)
for (int x=q[++head],i=0;i<4;i++){
int y=pam.Next[x][i];
if (!y)
continue;
dp[y]=min(dp[x]+1,pam.len[y]/2-pam.len[pam.Half[y]]+dp[pam.Half[y]]+1);
ans=min(ans,n-pam.len[y]+dp[y]);
q[++tail]=y;
}
printf("%d\n",ans);
}
return 0;
}

  

Codeforces Gym100543G Virus synthesis 字符串 回文自动机 动态规划的更多相关文章

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

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

  2. 洛谷P4762 [CERC2014]Virus synthesis(回文自动机+dp)

    传送门 回文自动机的好题啊 先建一个回文自动机,然后记$dp[i]$表示转移到$i$节点代表的回文串的最少的需要次数 首先肯定2操作越多越好,经过2操作之后的串必定是一个回文串,所以最后的答案肯定是由 ...

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

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

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

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

  5. BZOJ4044: [Cerc2014] Virus synthesis(回文树+DP)

    Description Viruses are usually bad for your health. How about fighting them with... other viruses? ...

  6. UVALive 6933 Virus synthesis(回文树)

    Viruses are usually bad for your health. How about ghting them with... other viruses? In this proble ...

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

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

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

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

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

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

随机推荐

  1. unit test

    1) State vs Behaviour Verificationhttps://manas.tech/blog/2009/04/30/state-vs-behaviour-verification ...

  2. CURL错误代码及含义

    https://curl.haxx.se/libcurl/c/libcurl-errors.html NAME libcurl-errors - error codes in libcurl DESC ...

  3. 【原创】大数据基础之Flume(2)应用之kafka-kudu

    应用一:kafka数据同步到kudu 1 准备kafka topic # bin/kafka-topics.sh --zookeeper $zk:2181/kafka -create --topic ...

  4. [Linux]流媒体服务器概述

    二.何为流媒体与流式传输? 2.1 流媒体 「流媒体」是指采用「流式传输」的方式在Internet播放的媒体格式,流媒体最大的特点就是「边下边播」,常用的流媒体格式有FLV(使用FLASH作为视频播放 ...

  5. tp5 设置layui分页

    \thinkphp\library\think\paginator\driver 添加 Layui.php <?php namespace think\paginator\driver; use ...

  6. C# 封装微信的模板消息

    1.先新建一个类库,以方便以后移植到其他的项目上继续使用,如何新建类库就自己去百度了哈,这里就不描述了,若有不会的朋友请留言哈.标红了的都要注意下咯. 2.先看看WxTemplate这个类文件的代码 ...

  7. vue 之 引入elementUI(两步走)

    1.npm 引入elementUI npm i element-ui -S 2.在main.js文件中全局引入 import ElementUI from 'element-ui' import 'e ...

  8. oracle数据库内存调整之增加内存

    注:本文来源:小颜Kevin   <oracle数据库内存调整之增加内存> 模拟操作系统内存从2G增加为8G后,调整数据库内存参数,示例中参数不作为实际生产环境参考,因为因需所取,调整参数 ...

  9. ssd.pytorch

    https://towardsdatascience.com/learning-note-single-shot-multibox-detector-with-pytorch-part-1-38185 ...

  10. Android 基础 二 四大组件 Activity

    Activity Intent IntentFilter 一理论概述 一. Activity 用来提供一个能让用户操作并与之交互的界面. 1.1 启动 startActivity(Intent int ...