• 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
    ", ans);
        }
        return 0;
    }
    /*
    4
    AAAA
    AGCTTGCA
    AAGGGGAAGGGGAA
    AAACAGTCCTGACAAAAAAAAAAAAC
    */
    
    
  • 相关阅读:
    各种不同的mq
    24. Swap Nodes in Pairs
    应用中有使用到集群么?多大规模?
    曹工杂谈:用好verbose,Jar包冲突不再难
    曹工杂谈:Java 类加载还会死锁?这是什么情况?
    Linux下使用docker 拉取 vsftpd 镜像搭建 Ftp 服务器,连接 Ftp 时遇到的错误(425 Failed to establish connection)
    曹工杂谈:Linux服务器上,Spring Boot 原地修改 jar 包配置文件/替换class文件,免去重复上传的麻烦
    曹工杂谈:手把手带你读懂 JVM 的 gc 日志
    曹工杂谈:一道阿里面试题,两个线程交替打印奇偶数
    曹工说Tomcat4:利用 Digester 手撸一个轻量的 Spring IOC容器
  • 原文地址:https://www.cnblogs.com/zxytxdy/p/11629138.html
Copyright © 2020-2023  润新知