bzoj4044: [Cerc2014] Virus synthesis 回文自动机

bzoj4044: [Cerc2014] Virus synthesis

Description

Viruses are usually bad for your health. How about fighting them with… other viruses? In
this problem, you need to find out how to synthesize such good viruses.
We have prepared for you a set of strings of the letters A, G, T and C. They correspond to the
DNA nucleotide sequences of viruses that we want to svnthesize, using the following operations:
* Adding a nucleotide either to the beginning or the end of the existing sequence
* Replicating the sequence, reversing the copied piece, and gluing it either to the beginmng or
to the end of the original (so that e.g., AGTC can become AGTCCTGA or CTGAAGTC).
We’re concerned about efficiency, since we have very many such sequences, some of them verv
long. Find a wav to svnthesize them in a mmimum number of operations.
你要用ATGC四个字母用两种操作拼出给定的串:
1.将其中一个字符放在已有串开头或者结尾
2.将已有串复制,然后reverse,再接在已有串的头部或者尾部
一开始已有串为空。求最少操作次数。
len<=100000

Input

The first line of input contains the number of test cases T. The descriptions of the test cases
follow:
Each test case consists of a single line containing a non-empty string. The string uses only
the capital letters A, C, G and T and is not longer than 100 000 characters.

Output

For each test case, output a single line containing the minimum total number of operations
necessary to construct the given sequence.

Sample Input

4
AAAA
AGCTTGCA
AAGGGGAAGGGGAA
AAACAGTCCTGACAAAAAAAAAAAAC

Sample Output

3
8
6
18

分析

很巧妙的回文自动机+Dp。
血赚的肯定是reverse操作。
reverse操作必定出回文串,并且长度是偶数。
fp f p 为构造出这个回文串上的最小步数
ans=min(len+fplenp,len) a n s = m i n ( l e n + f p − l e n p , l e n )
还有就是 fp=lenp(p=2k+1,kN) f p = l e n p ( p = 2 k + 1 , k ∈ N )
这样子的话转移为求 fp,p=2k,kN f p , p = 2 k , k ∈ N
首先,注意到回文串最后一步必定是reverse
所以假设回文串 p p 头尾去掉是回文串q的,把p翻转前加一个字母得到。
fp=fq+1 f p = f q + 1
还有一种情况把 p p 一半当成我们要求的模板串,得到和ans类似的转移
fp=lenp2+fqlenq+1
注意 q q 不超过p长度一半的子回文串。
q q <script type="math/tex" id="MathJax-Element-2603">q</script>用回文树维护一下,这题就切了。

代码

/**************************************************************
    Problem: 4044
    User: 2014lvzelong
    Language: C++
    Result: Accepted
    Time:4072 ms
    Memory:4436 kb
****************************************************************/

#include<cstdio>
#include<algorithm>
const int N = 1e5 + 10;
char s[N];
int fa[N], len[N], f[N], q[N], las[N], ch[N][4], n, last, sz;
int F(int p) {for(;s[n - len[p] - 1] != s[n]; p = fa[p]); return p;}
int idx(char ch){
    if(ch == 'A') return 0;
    if(ch == 'T') return 1;
    if(ch == 'C') return 2;
    if(ch == 'G') return 3;
}
void Init(int p, int l, int f) {
    ch[p][0] = ch[p][1] = ch[p][2] = ch[p][3] = 0;
    len[p] = l; fa[p] = f;
}
void Extend(int c) {
    int p = F(last);
    if(!ch[p][c]) {
        int np = ++sz; Init(ch[p][c] = np, len[p] + 2, ch[F(fa[p])][c]);
        if(len[np] <= 2) las[np] = fa[np];
        else {
            int x;
            for(x = las[p]; s[n - len[x] - 1] != s[n] || (len[x] + 2 << 1) > len[np]; x = fa[x]) ;
            las[np] = ch[x][c];
        }
    } last = ch[p][c];
}
void Build() {
    last = 0; sz = 1; n = 0; char ch = getchar();
    for(;ch < 'A' || ch > 'Z'; ch = getchar());
    for(;ch >= 'A' && ch <= 'Z'; ch = getchar()) Extend(s[++n] = idx(ch));
}
int main() {
    int T; scanf("%d", &T); 
    for(;T--;) {
        Init(0, 0, 1); Init(1, -1, 0); f[0] = fa[0] = 1; s[0] = -1;
        Build(); for(int i = 1;i <= sz; ++i) if(len[i] & 1) f[i] = len[i];
        int L, R, ans = n; q[L = R = 1] = 0;
        for(int u = q[L];L <= R; u = q[++L]) {
            for(int i = 0; i < 4; ++i) 
            if(ch[u][i]) {
                int v = ch[u][i];
                f[v] = std::min(f[u] + 1, len[v] / 2 + f[las[v]] - len[las[v]] + 1);
                ans = std::min(ans, f[v] + n - len[v]);
                q[++R] = v;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值