[回文自动机][DP] Codeforces gym 100543 G - Virus synthesis

本文介绍了一种基于回文自动机的动态规划算法,用于计算将任意字符串转换为回文串所需的最少操作次数。该算法通过维护每个节点代表的回文串长度及对应的最少操作次数来实现高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SolutionSolution

考虑在回文自动机上DP
fufu表示回文自动机中uu节点所代表的回文串最少需要几次才能得到

  • lenu为奇数,fu=lenufu=lenu
    • lenulenu为偶数,fu=min(fp+1,fhalfu+(lenu2lenhalfu)+1)fu=min(fp+1,fhalfu+(lenu2−lenhalfu)+1)

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 233333;
    
    int test, n;
    char chr[N];
    int s[N];
    int ch[N][10];
    int par[N], len[N];
    int rgt[N], half[N], f[N];
    int last, tcnt;
    
    inline void init(void) {
        for (int i = 0; i <= tcnt; i++) {
            half[i] = 0;
            for (int j = 0; j < 5; j++)
                ch[i][j] = 0;
        }
        par[0] = par[1] = 1;
        half[0] = half[1] = 1;
        len[1] = -1;
        f[0] = 1; f[1] = -1;
        tcnt = 1; last = 0;
    }
    inline void extend(int pos) {
        int p = last, key = s[pos];
        while (s[pos - len[p] - 1] != key) p = par[p];
        if (!ch[p][key]) {
            int np = ++tcnt, q = par[p];
            len[np] = len[p] + 2;
            while (s[pos - len[q] - 1] != key) q = par[q];
            par[np] = ch[q][key];
            q = half[p]; 
            while (len[ch[q][key]] > len[np] / 2 || s[pos - len[q] - 1] != key) q = par[q];
            half[np] = ch[q][key];
            if (len[np] & 1) {
                f[np] = len[np];
            } else {
                f[np] = min(f[p] + 1, f[half[np]] + len[np] / 2 - len[half[np]] + 1);
            }
            ch[p][key] = np;
        }
        last = ch[p][key];
    }
    
    int main(void) {
        freopen("1.in", "r", stdin);
        freopen("1.out", "w", stdout);
        scanf("%d\n", &test);
        while (test--) {
            scanf("%s", chr + 1);
            n = strlen(chr + 1);
            for (int i = 1; i <= n; i++)
                if (chr[i] == 'A') s[i] = 1;
                else if (chr[i] == 'T') s[i] = 2;
                else if (chr[i] == 'G') s[i] = 3;
                else if (chr[i] == 'C') s[i] = 4;
            init(); int ans = 1 << 30;
            for (int i = 1; i <= n; i++) {
                extend(i);
                ans = min(f[last] + n - len[last], ans);
            }
            cout << ans << endl;
        }
        return 0;
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值