zoukankan      html  css  js  c++  java
  • BZOJ 4044: [Cerc2014] Virus synthesis 回文自动机+DP

    Description

    Viruses are usually bad for your health. How about fighting them with... other viruses? In 
    this problem, you need to find out how to synthesize such good viruses. 
    We have prepared for you a set of strings of the letters A, G, T and C. They correspond to the 
    DNA nucleotide sequences of viruses that we want to svnthesize, using the following operations: 
    * Adding a nucleotide either to the beginning or the end of the existing sequence 
    * Replicating the sequence, reversing the copied piece, and gluing it either to the beginmng or 
    to the end of the original (so that e.g., AGTC can become AGTCCTGA or CTGAAGTC). 
    We're concerned about efficiency, since we have very many such sequences, some of them verv 
    long. Find a wav to svnthesize them in a mmimum number of operations. 
    你要用ATGC四个字母用两种操作拼出给定的串: 
    1.将其中一个字符放在已有串开头或者结尾 
    2.将已有串复制,然后reverse,再接在已有串的头部或者尾部 
    一开始已有串为空。求最少操作次数。 
    len<=100000 
     

    Input

    The first line of input contains the number of test cases T. The descriptions of the test cases 
    follow: 
    Each test case consists of a single line containing a non-empty string. The string uses only 
    the capital letters A, C, G and T and is not longer than 100 000 characters. 
     

    Output

    For each test case, output a single line containing the minimum total number of operations 
    necessary to construct the given sequence.

    字符串的构建过程一定是先构建出一个回文串,然后剩余字符一个个加到前面和后面.

    考虑构建回文自动机,那么对于自动机中的点 $x$,有 $f[x]$ 表示达到该目标最少操作次数.

    如果我们能求出 $f[x]$,那么答案就等于 $n+f[x]-len[x]$ 中最小的一个.

    考虑如何求解 $f[x]:$

    假如说 $x->y$ 有一条字符转移边,那么 $f[y]leqslant f[x]$,即可以将 $f[x]$ 的值赋给 $f[y]$.

    我们在构建自动机的时候再构建一个 $trans[x]$ 指针,来表示第一个长度小于等于 $len[x]/2$ 且是 $x$ 的回文后缀的位置.

    那么就有 $f[x]=f[trans[x]]+1+frac{len[x]}{2}-frac{len[trans[x]]}{2}$

    由于回文串的长度肯定是偶数的,所以我们只需扩展 $0$ 的所有出边即可,不必扩展 $1$ 的出边.

    扩展的时候 BFS 即可. 

    #include <cstdio> 
    #include <string> 
    #include <queue>
    #include <cstring>         
    #define N 100007 
    #define setIO(s) freopen(s".in","r",stdin) 
    using namespace std;             
    char S[N];   
    queue<int>q; 
    int tot,last,n;   
    int ch[N][4],len[N],pre[N],ss[N],trans[N],f[N]; 
    void Initialize() { pre[0]=1,len[1]=-1,ss[0]=-1,tot=1; }  
    int newnode(int x) { return len[++tot]=x,tot; } 
    int getfail(int p,int i) 
    {
        while(ss[i-len[p]-1]!=ss[i]) p=pre[p]; 
        return p;   
    }
    void extend(int c,int i) 
    { 
        int p=getfail(last,i);    
        if(!ch[p][c]) 
        {
            int q=newnode(len[p]+2); 
            pre[q]=ch[getfail(pre[p],i)][c],ch[p][c]=q;        
            if(len[q]<=2) trans[q]=pre[q];    
            else 
            {
                int tmp=trans[p]; 
                while(ss[i-len[tmp]-1]!=ss[i]||((len[tmp]+2)<<1)>len[q]) tmp=pre[tmp];  
                trans[q]=ch[tmp][c];    
            }
        }    
        last=ch[p][c];         
    }
    void clr() 
    {
        for(int i=0;i<=tot;++i) 
        {
            pre[i]=len[i]=0;
            memset(ch[i],0,sizeof(ch[i])); 
        }
        tot=0; 
    }
    void solve()
    { 
        int i,j,ans; 
        scanf("%s",S+1),n=strlen(S+1),ans=n,Initialize(); 
        for(i=1;i<=n;++i) 
        {
            if(S[i]=='A') ss[i]=0; 
            if(S[i]=='G') ss[i]=1; 
            if(S[i]=='C') ss[i]=2; 
            if(S[i]=='T') ss[i]=3;  
        }   
        for(i=1;i<=n;++i) extend(ss[i],i); 
        for(i=2;i<=tot;++i) f[i]=len[i];   
        for(i=0;i<4;++i) if(ch[0][i]) q.push(ch[0][i]);   
        while(!q.empty()) 
        {
            int x=q.front();q.pop(); 
            f[x]=min(f[x],f[trans[x]]+1+len[x]/2-len[trans[x]]);       
            ans=min(ans,n-len[x]+f[x]);  
            for(i=0;i<4;++i) 
            {
                if(!ch[x][i]) continue;  
                int y=ch[x][i]; 
                f[y]=min(f[y],f[x]+1);  
                q.push(y); 
            }
        } 
        printf("%d
    ",ans),clr(); 
    }
    int main() 
    { 
        // setIO("input");  
        int T; 
        scanf("%d",&T); 
        while(T--) solve();  
        return 0; 
    }
    

      

  • 相关阅读:
    移除“xmlns”命名空间
    求质数几种算法
    删除重复字符串的算法
    第一章 搭建一个通用的.net core项目框架
    LSJ_NHibernate第四章 MVC
    LSJ_NHibernate第三章 IDAL,DAL,BLL
    LSJ_NHibernate第二章 ManagerPage
    LSJ_NHibernate第一章 NHibernate介绍
    SQL Server2008R无法登录的解决方案(系统文件损坏)1814 18456....不看别后悔,有用请点赞
    lsjORM ----让开发变得更加快捷(二)
  • 原文地址:https://www.cnblogs.com/guangheli/p/12132623.html
Copyright © 2011-2022 走看看