博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Bzoj4044 Virus synthesis
阅读量:6212 次
发布时间:2019-06-21

本文共 2341 字,大约阅读时间需要 7 分钟。

题意

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

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

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

\(len\le100000\)

Sol

首先有个结论

每次形成偶数长度回文串的最后一步一定是操作 \(2\)
那么考虑一个 \(DP\)
\(f[i]\) 表示形成 \(i\) 表示的字符串需要的最少步数
可以去掉首和尾转移来,可以由它的一个前缀或者后缀转移来
如果是个偶数长度的字符串
可以由某个长度小于等于它一半的字符串增长到它的长度后翻倍而来
可以由它去掉首尾的串一步转移而来,因为去掉首位仍然是偶数长度而且形成偶数长度回文串的最后一步一定是操作 \(2\)

那么直接用回文树实现

求某个长度小于等于它一半的字符串直接建树的时候暴力跳一下(雾

# include 
# define IL inline# define RG register# define Fill(a, b) memset(a, b, sizeof(a))using namespace std;typedef long long ll;IL int Input(){ RG int x = 0, z = 1; RG char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1; for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z;}const int maxn(1e5 + 5);int f[maxn], son[4][maxn], trans[666], half[maxn], len[maxn], fa[maxn], num[maxn], tot, last, pre[maxn];char s[maxn];IL void Init(){ for(RG int i = 0; i <= tot; ++i){ len[i] = fa[i] = half[i] = 0; for(RG int j = 0; j < 4; ++j) son[j][i] = 0; } fa[0] = fa[1] = 1, len[1] = -1, tot = 1, last = 0;}IL void Extend(RG int pos, RG int c){ RG int p = last; while(s[pos - len[p] - 1] != s[pos]) p = fa[p]; if(!son[c][p]){ RG int np = ++tot, q = fa[p]; while(s[pos - len[q] - 1] != s[pos]) q = fa[q]; len[np] = len[p] + 2, fa[np] = son[c][q]; son[c][p] = np, pre[np] = p; if(s[pos - len[half[p]] - 1] == s[pos]) half[np] = son[c][half[p]]; else half[np] = fa[np]; while((len[half[np]] << 1) > len[np]) half[np] = fa[half[np]]; } last = son[c][p];}int main(){ trans['C'] = 1, trans['G'] = 2, trans['T'] = 3; for(RG int t = Input(), n = 0; t; --t){ Init(), scanf(" %s", s + 1), n = strlen(s + 1); for(RG int i = 1; i <= n; ++i) Extend(i, trans[s[i]]); RG int ans = n; for(RG int i = 2; i <= tot; ++i){ f[i] = min(len[i], f[fa[i]] + len[i] - len[fa[i]]); if(len[i] & 1) f[i] = min(f[pre[i]] + 2, f[i]); else{ f[i] = min(f[i], pre[i] ? f[pre[i]] + 1 : 2); f[i] = min(f[i], f[half[i]] + (len[i] >> 1) - len[half[i]] + 1); } ans = min(ans, f[i] + n - len[i]); } printf("%d\n", ans); } return 0;}

转载于:https://www.cnblogs.com/cjoieryl/p/9153725.html

你可能感兴趣的文章
[转]MPI--MPI+VS2010 配置及编译
查看>>
L171
查看>>
nodeJS之HTTP
查看>>
poj2748
查看>>
poj2546
查看>>
windows运维如何批量远程桌面
查看>>
DB2 数据库的安装配置及监控
查看>>
IIS应用程序扩展名映射中无法添加“.svc”的问题
查看>>
ssd存储的SLC、MLC、TLC闪存芯片颗粒有什么区别?
查看>>
「小程序JAVA实战」小程序的flex布局(22)
查看>>
maven项目没有错,但是在项目头上有红叉的解决方法
查看>>
Hibernate注解与JPA
查看>>
34.Intellij IDEA 安装lombok及使用详解
查看>>
Educational Codeforces Round 26 - A, B, C 思维
查看>>
使用UIBezierPath绘制图形
查看>>
oracle 表达式运算符优先级
查看>>
动态规划-导弹拦截(求最长不上升子序列和最长上升子序列)
查看>>
Django框架基础
查看>>
Codeforces Round #547 (Div. 3) B.Maximal Continuous Rest
查看>>
过滤器
查看>>