UVALive - 6933 C - Virus synthesis

题意:

两个操作:在一个串前面或后面添加一个字母。把当前这个串double一下变成回文。

询问一个串的最小操作步数,开始为空。

题解:

答案肯定是一个回文子串的最小步数加上剩下的一个个添。

一个回文串s可以从两边加同一个字母一步花费转移过来,或者从长度小于|s|/2的回文后缀转移过来。

回文树上dp,维护长度小于一半的后缀link

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         #include 
        
          #include 
          #include 
          
            #include 
           
             #include 
            
              using namespace std; #define N 200010 #define M 2000010 #define ULL unsigned long long #define LL long long #define ls (i << 1) #define rs (ls | 1) #define md ((ll + rr) >> 1) #define lson ll, md, ls #define rson md + 1, rr, rs #define inf 0x3f3f3f3f #define eps 1e-4 #define pii pair 
             
               #define MP make_pair #define mod 1000000007 int n; int ans; char s[N]; struct PT { int S[N], n, len[N], last, fail[N], h[N]; int dp[N]; int nxt[N][4], tot; int newnode(int l) { int k = tot++; len[k] = l; memset(nxt[k], 0, sizeof nxt[k]); return k; } void init() { tot = 0; newnode(0); newnode(-1); S[n=0] = -1; last = fail[1] = fail[0] = 1; h[0] = h[1] = 1; dp[0] = 1; } int get(int x) { while(S[n-len[x]-1] != S[n]) x = fail[x]; return x; } void add(int c) { S[++n] = c; int cur = get(last); if(nxt[cur][c] == 0) { int now = newnode(len[cur] + 2); fail[now] = nxt[get(fail[cur])][c]; nxt[cur][c] = now; if(len[now] % 2 == 0) { h[now] = h[cur]; for(int &i = h[now]; S[n-len[i]-1] != S[n] || len[i] + 2 > len[now]/2;) { i = fail[i]; while(len[i] >= 0 && len[i] & 1) i = fail[i]; } h[now] = len[h[now]] >= 0 ? nxt[h[now]][c] : 0; dp[now] = min(dp[cur] + 1, len[now]/2 - len[h[now]] + dp[h[now]] + 1); ans = min(ans, ::n - len[now] + dp[now]); //printf("n %d len[%d]:%d dp %d h %d ans %d\n", n, now, len[now], dp[now], len[h[now]], ans); } } last = nxt[cur][c]; } }go; int get(char c) { if(c == 'A') return 0; else if(c == 'T') return 1; else if(c == 'C') return 2; return 3; } int main() { int T; scanf("%d", &T); while(T--) { scanf("%s",s); n = strlen(s); ans = n; go.init(); for(int i = 0; i < n; ++i) go.add(get(s[i])); printf("%d\n", ans); } } 
              
             
            
           
         
       
      
      
     
     
    
    
   
   

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值