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\n",PAM::solve());
90     }
91     return 0;
92 }

 

posted @ 2018-12-20 14:59  guapisolo  阅读(216)  评论(0编辑  收藏  举报