zoukankan      html  css  js  c++  java
  • 洛谷P4762 [CERC2014]Virus synthesis(回文自动机+dp)

    传送门

    回文自动机的好题啊

    先建一个回文自动机,然后记$dp[i]$表示转移到$i$节点代表的回文串的最少的需要次数

    首先肯定2操作越多越好,经过2操作之后的串必定是一个回文串,所以最后的答案肯定是由一个回文串+不断暴力添加得来,那么答案就是$min(ans,dp[i]+n-len[i])$

    然后对于一个串$i$,如果它在前面和后面加上一个字母可以形成回文串$j$,则$dp[j]=dp[i]+1$

    为啥嘞?我们可以假设在形成$i$的之前一步把这个字母加上去,执行2操作后就可以变成$j$了

    然后我们可以fail指针找到最长的回文串$x$满足$len[x]<=len[i]/2$,那么$dp[i]=min(dp[i],dp[x]+1+len[i]/2-len[x])$(先暴力填好一半,剩下的用2操作)

    然后可以用队列记录状态,保证转移至有序的

    至于怎么找$x$,我们可以直接在建自动机的时候顺便求出来,就是多跳几次。这个看代码好了

     1 //minamoto
     2 #include<cstring>
     3 #include<cstdio>
     4 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
     5 const int N=2e5+5,M=5;
     6 char s[N];int dp[N],len[N],fail[N],ch[N][M];
     7 int trans[N],last,p,q,str[N],tot,ans,n,qu[N];
     8 int val[105];
     9 inline int newnode(int x){
    10     len[++tot]=x;memset(ch[tot],0,sizeof(ch[tot])*5);return tot;
    11 }
    12 inline int getfail(int x,int n){
    13     while(s[n-len[x]-1]!=s[n]) x=fail[x];return x;
    14 }
    15 inline void init(){
    16     val['A']=0,val['T']=1,val['C']=2,val['G']=3;
    17     s[0]=-1,fail[0]=1,last=0;
    18     len[0]=0,len[1]=-1,tot=1;
    19     memset(ch[0],0,sizeof(int)*5),memset(ch[1],0,sizeof(int)*5);
    20 }
    21 void ins(int c,int i){
    22     p=getfail(last,i);
    23     if(!ch[p][c]){
    24         q=newnode(len[p]+2);
    25         fail[q]=ch[getfail(fail[p],i)][c];
    26         ch[p][c]=q;
    27         if(len[q]<=2) trans[q]=fail[q];
    28         else{
    29             int tmp=trans[p];
    30             while(s[i-1-len[tmp]]!=s[i]||(len[tmp]+2)*2>len[q]) tmp=fail[tmp];
    31             trans[q]=ch[tmp][c];
    32         }
    33     }
    34     last=ch[p][c];
    35 //    printf("%d
    ",last);
    36 }
    37 int main(){
    38 //    freopen("testdata.in","r",stdin);
    39     int T;scanf("%d",&T);
    40     while(T--){
    41         scanf("%s",s+1);
    42         init(),ans=n=strlen(s+1);
    43         for(int i=1;i<=n;++i) ins(val[s[i]],i);
    44         for(int i=2;i<=tot;++i) dp[i]=len[i];
    45         int h=1,t=0;qu[++t]=0,dp[0]=1;
    46         while(h<=t){
    47             int u=qu[h++];
    48             for(int i=0;i<4;++i){
    49                 int x=ch[u][i];
    50                 if(!x) continue;
    51                 dp[x]=dp[u]+1;
    52                 int y=trans[x];
    53                 cmin(dp[x],dp[y]+1+len[x]/2-len[y]);
    54                 cmin(ans,dp[x]+n-len[x]);
    55                 qu[++t]=x;
    56             }
    57         }
    58         printf("%d
    ",ans);
    59     }
    60     return 0;
    61 }
  • 相关阅读:
    什么是 CLR
    常用的数据结构以及算法
    Array和ArrayList的异同点
    什么是CMS?
    .NET Framework3.0答疑
    C#中的委托
    C#速成之三(Quick C#)
    C#速成之五(Quick C#)
    C#速成之四(Quick C#)
    类,对象,封装,接口,多态,继承
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9630381.html
Copyright © 2011-2022 走看看