P4762 [CERC2014]Virus synthesis
题意
真是道回文自动机好题。
首先考虑答案必定是一个回文串+剩余部分的形式,因此可以建出回文自动机,之后考虑每个长度为偶数的回文串。
对于一个长度为偶数的回文串,设它在回文自动机上对应的节点为\(x\),我们对于每个\(x\)求出\(trans_x\)表示x的最长后缀回文串,满足\(len_{trans_x}\leqslant len_x/2\)。
之后设\(f_x\)表示\(x\)拼成\(x\)这个串的最小代价,我们从\(0\)(偶根)出发进行\(bfs\),中途计算\(f_x\)。
对于\(f_x\):
初值肯定是自身长度\(f_x=len_x\)。
如果存在一条边\((x,y)\),那么\(f_y=f_x+1\),因为我们可以在拼\(x\)时还没进行\(2\)操作时向\(x\)后面填一个字符,使其进行\(2\)操作后变为\(y\)。
同时\(f_x=min(f_x,f_{trans_x}+1+lem_x/2-len_{trans_x})\),即我们可以从\(trans_x\)变过来。
对于每个\(x\),它对答案的贡献是\(n-len_x+f_x\),\(n\)是字符串长度。
code:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int inf=1e9;
int T,n,tot,last,ans;
int fail[maxn],len[maxn],trans[maxn],f[maxn];
int ch[maxn][5];
char s[maxn];
inline int change(char c)
{
if(c=='A')return 1;
if(c=='G')return 2;
if(c=='C')return 3;
if(c=='T')return 4;
return 2333;
}
inline void init()
{
for(int i=0;i<=tot;i++)
for(int j=1;j<=4;j++)
ch[i][j]=0;
fail[0]=1;len[1]=-1;
tot=1;last=0;
}
inline int getfail(int x,int pos)
{
while(s[pos-len[x]-1]!=s[pos])x=fail[x];
return x;
}
inline void add(int c,int pos)
{
int p=getfail(last,pos);
if(!ch[p][c])
{
int q=++tot,tmp;len[q]=len[p]+2;
tmp=getfail(fail[p],pos);
fail[q]=ch[tmp][c];ch[p][c]=q;
if(len[q]<=2)trans[q]=fail[q];
else
{
tmp=trans[p];
while(s[pos-len[tmp]-1]!=s[pos]||((len[tmp]+2)<<1)>len[q])tmp=fail[tmp];
trans[q]=ch[tmp][c];
}
}
last=ch[p][c];
}
inline void solve()
{
queue<int>q;
for(int i=2;i<=tot;i++)f[i]=len[i];
for(int i=1;i<=4;i++)if(ch[0][i])q.push(ch[0][i]);
while(!q.empty())
{
int x=q.front();q.pop();
f[x]=min(f[x],f[trans[x]]+1+len[x]/2-len[trans[x]]);
ans=min(ans,n-len[x]+f[x]);
for(int i=1;i<=4;i++)
{
if(!ch[x][i])continue;
int y=ch[x][i];
f[y]=min(f[y],f[x]+1);
q.push(y);
}
}
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%s",s+1);n=strlen(s+1);
s[0]='#';
init();
for(int i=1;i<=n;i++)add(change(s[i]),i);
ans=n;solve();
printf("%d\n",ans);
}
return 0;
}
P4762 [CERC2014]Virus synthesis的更多相关文章
- BZOJ 4044 Luogu P4762 [CERC2014]Virus Synthesis (回文自动机、DP)
好难啊..根本不会做..基本上是抄Claris... 题目链接: (bzoj)https://www.lydsy.com/JudgeOnline/problem.php?id=4044 (luogu) ...
- 洛谷P4762 [CERC2014]Virus synthesis(回文自动机+dp)
传送门 回文自动机的好题啊 先建一个回文自动机,然后记$dp[i]$表示转移到$i$节点代表的回文串的最少的需要次数 首先肯定2操作越多越好,经过2操作之后的串必定是一个回文串,所以最后的答案肯定是由 ...
- luogu P4762 [CERC2014]Virus synthesis (回文自动机)
大意: 初始有一个空串, 操作(1)在开头或末尾添加一个字符. 操作(2)在开头或末尾添加该串的逆串. 求得到串$S$所需最少操作数. 显然最后一定是由某个偶回文通过添加字符得到的, 那么只需要求出所 ...
- luogu_4762: [CERC2014]Virus synthesis
洛谷_4762:[CERC2014]Virus synthesis 题目描述: 初始有一个空串,利用下面的操作构造给定串\(S\).\(len(S)\leq10^5\) 1: 串开头或末尾加一个字符. ...
- [CERC2014]Virus synthesis【回文自动机+DP】
[CERC2014]Virus synthesis 初始有一个空串,利用下面的操作构造给定串 SS . 1.串开头或末尾加一个字符 2.串开头或末尾加一个该串的逆串 求最小化操作数, \(|S| \l ...
- bzoj4044/luoguP4762 [Cerc2014]Virus synthesis(回文自动机+dp)
bzoj4044/luoguP4762 [Cerc2014]Virus synthesis(回文自动机+dp) bzoj Luogu 你要用ATGC四个字母用两种操作拼出给定的串: 1.将其中一个字符 ...
- bzoj4044 [Cerc2014] Virus synthesis
回文自动机上dp f[x]表示形成x代表的回文串所需的最小步数, 若len[x]为奇数,f[x]=len[x],因为即使有更优的,也是直接添加,没有复制操作,那样就不用从x转移了. 若len[x]为偶 ...
- [CERC2014] Virus synthesis
设f[i]为形成极长回文串i的最小操作数.答案为min f[i]+n-len[i]. 在不形成偶回文的情况下形成奇回文的最小操作数为该串长度.可以不考虑(但ans赋为len). 正确性基于: 1)奇. ...
- bzoj 4044: [Cerc2014] Virus synthesis【回文自动机+dp】
建回文自动机,注意到一个回文串是可以通过一个长度小于等于这个串长度的一半的回文串添上一些字符然后复制得到的,也就是在自动机上向fa走,相当于treedp 每次都走显然会T,记录一个up,指向祖先中最下 ...
随机推荐
- 搭建自己的企业级镜像仓库-Harbor
网上资料很多,在这记录一下思路 1 安装Docker 2 安装Docker Compose apt-get install docker-compose3 下载最新版Harbor在线安装包,例如 ha ...
- Provide Several View Variants for End-Users 为最终用户提供多个视图变体
In this lesson, you will learn how to provide several customized variants of the same View, and allo ...
- 1、netty入门说明
netty中的例子,基本模式都是:server -> Initializer -> Handler . 在server中去启动线程,打开端口,设置initializer,和一些启动的参数配 ...
- Python读字节某一位的值,设置某一位的值,二进制位操作
Python读字节某一位的值,设置某一位的值,二进制位操作 在物联网实际应用项目开发中,为了提升性能,与设备端配合,往往最终使用的是二进制字节串方式进行的通信协议封装,更会把0和1.True和Fa ...
- 表单生成器(Form Builder)之mongodb表单数据查询——统计查询求和
上一篇笔记仅是记录了一下简单的关联查询,根据笔记中的场景:将某一车辆关联的耗损记录全部放在了一个字段当中.不知道现在中有没有这种场景,我们的应用中没有类似的场景,可能我们更关注的是某车辆的总耗损金额和 ...
- Python如何动态的为对象添加方法或属性,__slots__用法
代码示例如下: import types #使用MethodType方法需要导入包 class test(object): #定义 一个test类,包含name属性和f()方法 def __i ...
- Qt的诞生和本质
有没有发现,在这个主函数里面没有了消息循环了.消息循环到哪里去了呢? 我们知道,每个GUI应用程序都有消息循环,一般都需要将消息循环while那个函数写到main的最后位置.那既然如此,为了代码复用, ...
- 菜鸟刷面试题(一、Java基础篇)
目录: JDK 和 JRE 有什么区别? == 和 equals 的区别是什么? 两个对象的 hashCode()相同,则 equals()也一定为 true,对吗? final 在 java 中有什 ...
- 第一篇:C++之hello world
1.编辑器:Microsoft Visual C++ 2010,下载安装 2.新建项目 代码: #include <iostream>#include <Windows.h>/ ...
- typescript与nodejs(二)基于装饰器实现路由表
之前实现了一个简单的WebServer 但是这离实际使用还有一点距离 webserver 首先面对第一个问题是路由表 啥是路由表 路由表别看听起来神秘,但是其实就是 if else onhttp- { ...