zoukankan      html  css  js  c++  java
  • BZOJ 4044 Virus synthesis (回文自动机+dp)

    题目大意:

    你可以在一个串的开头或者末尾加入一个字符,或者把当前整个串$reverse$,然后接在前面或者后面,求达到目标串需要的最少操作次数

    对目标串建出$PAM$

    定义$dp[x]$表示当前在回文树的x节点,拼凑出这个节点表示的回文串所需要的最小操作次数

    $fa_{x}$表示沿着树边指向它的父亲,$pre_{x}$表示它的$fail$指针

    如果它是奇回文串,一定不能被翻转得到,所以开头结尾各需要加上一个字符,$dp[x]=dp[fa_{x}]+2$

    如果它是偶回文串,可以被翻转得到

    1.要么是在上次翻转之前先添加一个字符,再翻转得到,$dp[x]=dp[fa_{x}]+1$

    2.要么是在这次进行翻转,需要保证被翻转的串长度不大于$dep[x]/2$

    可以在回文树上倍增跳$pre$,找到$x$的一个长度不大于$dep[x]/2$的回文后缀所在节点$y$

    只需要找后缀的情况即可,其他的情况会被合并到情况一里

    剩下的部分也要被暴力地填上,那么$dp[x]=dp[y]+dep[x]/2-dep[y]+1$

     1 #include <cmath>
     2 #include <vector>
     3 #include <cstdio>
     4 #include <cstring>
     5 #include <algorithm>
     6 #define N1 100100
     7 #define S1 (N1<<1)
     8 #define ll long long
     9 #define uint unsigned int
    10 #define rint register int 
    11 #define dd double
    12 #define il inline 
    13 #define inf 0x3f3f3f3f
    14 using namespace std;
    15 
    16 int len,T;
    17 inline int idx(char x)
    18 {
    19     if(x=='A') return 0;
    20     if(x=='C') return 1;
    21     if(x=='G') return 2;
    22     if(x=='T') return 3;
    23 }
    24 char str[N1];
    25 int lg[N1];
    26 namespace PAM{
    27 int trs[N1][4],pre[N1],dep[N1],fa[N1],dp[N1],la,tot;
    28 int ff[N1][17];
    29 void init()
    30 {
    31     tot++;
    32     memset(trs,0,tot*4*4),memset(pre,0,tot*4);
    33     memset(ff,0,tot*4*16),memset(fa,0,tot*4);
    34     memset(dp,0,tot*4),memset(dep,0,tot*4);
    35     la=tot=1,dep[1]=-1;pre[0]=pre[1]=1;
    36 }
    37 int chk(char *str,int i,int p){return str[i-dep[p]-1]!=str[i]?1:0;}
    38 void insert(char *str,int i)
    39 {
    40     int p=la,np,fp,c=idx(str[i]);
    41     while(chk(str,i,p)) p=pre[p];
    42     if(!trs[p][c])
    43     {
    44         np=++tot;
    45         dep[np]=dep[p]+2;
    46         fp=pre[p];
    47         while(chk(str,i,fp)) fp=pre[fp];
    48         pre[np]=trs[fp][c];
    49         trs[p][c]=np;
    50         fa[np]=p;
    51     }
    52     la=trs[p][c];
    53 }
    54 int solve()
    55 {
    56     int i,j,x,ans=len,de;
    57     ff[0][0]=ff[0][1]=ff[1][0]=ff[1][1]=0;
    58     for(i=2;i<=tot;i++) ff[i][0]=i,ff[i][1]=pre[i];
    59     for(j=2;j<=16;j++)
    60         for(i=2;i<=tot;i++)
    61             ff[i][j]=ff[ ff[i][j-1] ][j-1];
    62     dp[0]=1,dp[1]=-1;
    63     for(i=2;i<=tot;i++)
    64     {
    65         x=i;
    66         dp[i]=dp[fa[i]]+((dep[i]&1)?2:1);
    67         if((dep[i]&1)) continue;
    68         for(j=lg[dep[i]];j>=0;j--)
    69             if(dep[ff[x][j]]>=dep[i]/2) x=ff[x][j];
    70         if(dep[x]>dep[i]/2) x=pre[x];
    71         dp[i]=min(dp[i],dp[x]+1+dep[i]/2-dep[x]);
    72         ans=min(ans,len-dep[i]+dp[i]);
    73     }
    74     return ans;
    75 }
    76 };
    77 
    78 int main()
    79 {
    80     scanf("%d",&T);
    81     while(T--)
    82     {
    83         scanf("%s",str+1);
    84         len=strlen(str+1);
    85         int i;
    86         for(lg[1]=0,i=2;i<=len;i++) lg[i]=lg[i>>1]+1;
    87         PAM::init();
    88         for(i=1;i<=len;i++) PAM::insert(str,i);
    89         printf("%d
    ",PAM::solve());
    90     }
    91     return 0;
    92 }
  • 相关阅读:
    [BZOJ5338][TJOI2018]xor(可持久化Trie)
    [BZOJ4592][SHOI2015]脑洞治疗仪(线段树)
    [BZOJ4571][SCOI2016]美味(贪心+主席树)
    [BZOJ4570][SCOI2016]妖怪(凸包)
    [BZOJ4569][SCOI2016]萌萌哒(倍增+并查集)
    [BZOJ4567][SCOI2016]背单词(Trie+贪心)
    [BZOJ4565][HAOI2016]字符合并(区间状压DP)
    [BZOJ4561][JLOI2016]圆的异或并(扫描线)
    [BZOJ2650]积木
    [清橙A1210]光棱坦克
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10149402.html
Copyright © 2011-2022 走看看