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

Solution S o l u t i o n

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

  • lenu为奇数, fu=lenu f u = l e n u

    • lenu l e n u 为偶数, fu=min(fp+1,fhalfu+(lenu2lenhalfu)+1) f u = min ( f p + 1 , f h a l f u + ( l e n u 2 − l e n h a l f u ) + 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;
      }
      
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值