luogu_4762: [CERC2014]Virus synthesis

洛谷_4762:[CERC2014]Virus synthesis

题目描述:

  • 初始有一个空串,利用下面的操作构造给定串\(S\)\(len(S)\leq10^5\)
    • 1: 串开头或末尾加一个字符。
    • 2: 串开头或末尾添加一个该串的逆串。

输入描述:

  • 给出一个\(T\)表示要处理的字符串的数量。
  • 接下来第\(2\)~\(T+1\)行每行给出一个字符串。

输出描述:

  • 对于每一个字符串,输出一个正整数表示答案。

思路:

  • 回文自动机。
  • 先建立一个回文自动机,然后记\(f(i)\)表示转移到\(i\)节点结尾代表的回文串的最少需要的次数。
  • 操作\(2\)肯定越多越好,经过操作\(2\)得到的肯定是一个回文串,那么最后的答案肯定是回文串\(+\)暴力
    • 可以知道最后答案为\(ans=min(ans,f(i)+strlen-len(i))\)
  • 对于一个串\(i\),如果在他前面和后面加上一个相同的字母可以形成回文串\(j\),则\(f(j)=f(i)+1\)
  • 为什么是对的呢?就相当于形成\(i\)只有回文串的前一半,先在前一半的前面加上那个字母后再进行操作\(2\)就可以变成字符串\(j\)了。
  • 对应在自动机里就是如果一个节点有子节点,那么\(f(son)=f(fa)+1\)
  • 对于遍历到的位置\(x\),他的\(trans\)指针指向\(y\),那么有\(f(x)=min(f(x),f(y)+\:(len(x)/2-len(y))\:+1)\)
  • 最后对\(trie\)图进行\(bfs\)更新答案。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 +10, INF = 0x3f3f3f3f;
int T, ans;

char s[maxn];
int cnt, trie[maxn][6], trans[maxn], w[110];
int len[maxn], fail[maxn], len_str, last;

int f[maxn];

void init()
{
    w['A'] = 0, w['T'] = 1, w['C'] = 2, w['G'] = 3;
    scanf("%s", s + 1);
    len_str = ans = strlen(s + 1);
    cnt = 1, last = 0;
    len[0] = 0, len[1] = -1;
    fail[0] = 1, fail[1] = 0;
    memset(trie[0], 0, sizeof(trie[0]));
    memset(trie[1], 0, sizeof(trie[1]));
}

inline int get_fail(int las, int i)
{
    while(s[i - len[las] - 1] != s[i])
        las = fail[las];
    return las;
}

void build_PAM()
{
    for(int i = 1; i <= len_str; i++)
    {
        int num = w[int(s[i])];
        int p = get_fail(last, i);
        if(!trie[p][num])
        {
            len[++cnt] = len[p] + 2;
            memset(trie[cnt], 0, sizeof(trie[cnt]));
            fail[cnt] = trie[get_fail(fail[p], i)][num];
            trie[p][num] = cnt;

            //--------求trans指针
            if(len[cnt] <= 2) trans[cnt] = fail[cnt];
            else
            {
                int tmp = trans[p];
                while((s[i - len[tmp] - 1] != s[i]) || ( ((len[tmp] + 2) * 2) > len[cnt]))
                    tmp = fail[tmp];
                trans[cnt] = trie[tmp][num];
            }
            //--------
        }
        last = trie[p][num];
    }
}

int main()
{
    scanf("%d", &T);
    while(T--)
    {
        init(); build_PAM();
        for(int i = 2; i <= cnt; i++)
            f[i] = len[i]; f[0] = 1;
        queue<int> q; q.push(0);
        while(q.size())
        {
            int t = q.front(); q.pop();
            for(int i = 0, x, y; i <= 3; i++)
            {
                x = trie[t][i]; if(!x) continue;
                f[x] = f[t] + 1; y = trans[x];
                f[x] = min(f[x], f[y]+1+len[x]/2-len[y]);
                ans = min(ans, f[x]+len_str-len[x]);
                q.push(x);
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}
/*
4
AAAA
AGCTTGCA
AAGGGGAAGGGGAA
AAACAGTCCTGACAAAAAAAAAAAAC
*/

posted @ 2019-10-07 00:42  zhaoxiaoyun  阅读(123)  评论(0编辑  收藏  举报