1. 程式人生 > >[BZOJ4044]Virus synthesis 回文自動機的DP

[BZOJ4044]Virus synthesis 回文自動機的DP

repl strlen 長度 貢獻 rac nth begin 回文自動機 ....

4044: [Cerc2014] Virus synthesis

Time Limit: 20 Sec Memory Limit: 128 MB

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.

Sample Input

4
AAAA
AGCTTGCA
AAGGGGAAGGGGAA
AAACAGTCCTGACAAAAAAAAAAAAC

Sample Output

3
8
6
18
題解: 這道題是一道回文自動機的DP好題啊。。。很難想,解釋起來似乎也很混亂, 有不明白歡迎詢問,因為這樣寫題解也不能完全解釋明白233 我們考慮,假設答案為ans,那初始化ans=串長. 如果ans能夠減小,那一定是某一個回文串通過復制來做出的貢獻. 註意,只能是一個,因為一旦復制就要復制全串, 最終的目標串一定是添加字符(可以是0個,即不添加)形成的,而不可能有兩段復制. 由於這是一個回文有關題目......manacher看起來還不能搞 所以我們只好先把回文自動機建出來,對於回文自動機上每個節點i設f[i]表示生成節點i代表的串所需要的最少操作次數 那麽這個串的生成可以是在對稱軸外側填字符+復制,也可以是在對稱軸內側填字符+復制 如果是在外側: 假設串i可以在串j復制之前在外側添加一個字符+復制得到, 那麽我們可以想到,f[i]=min(f[j]+1)
或者,f[i]可以通過某個回文後綴對稱軸內側填字符+復制得到, 那麽這個回文後綴的長度一定小於len[i]/2 回文後綴我們可以通過暴力跳fail指針來尋找 轉移方程為f[i]=min(len[i]/2+f[j]-len[j]+1) 但是對於本題的數據範圍這樣會T掉…… 那麽我們考慮,對於i的某個可行復制串回文字串j,以及fail[j] f[j]-len[j]的值顯然要大於f[fail[j]]-len[fail[j]],那麽我們只需要考慮第一個合法決策點,比它長的不會更優秀 但是這樣還是會T…… 所以我們考慮對於某個節點i,我們可以記錄它的第一個最優決策點。 那麽它的最優決策點可以從它的fail的最優決策點開始選擇 (由於i和fail[i]的查找路徑是一樣的,len[fail]比len[i]長度更短,那麽對於fail合法對於i也會合法) 所以在尋找i的決策點時,我們從fail[i]的最優決策點開始查找即可。 這樣構建回文自動機的時候處理決策點,再遍歷一遍求出每個串的f值,最後答案就是ans=min(n-len[i]+f[i]) 代碼實現:
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 const int N=100010,inf=0x7fffffff;
 6 char s[N];
 7 struct Pam_Tree
 8 {
 9     int n,m,last,p,strategy[N];
10     int ch[N][4],len[N],fail[N],f[N];
11     int q[N],hd,tl;
12     inline int id(char x)
13     {
14         switch(x)
15         {
16             case A:return 0;
17             case C:return 1;
18             case G:return 2;
19             case T:return 3;
20         }
21         return 0;
22     }
23     inline int newnode(int l)
24     {
25         len[p]=l;memset(ch[p],0,sizeof(ch[p]));
26         fail[p]=f[p]=strategy[p]=0;
27         return p++;
28     }
29     inline int getfail(int x)
30     {
31         while(s[n-len[x]-1]!=s[n])x=fail[x];
32         return x;
33     }
34     inline void work()
35     {
36         register int i,x,u;
37         hd=1,tl=0,q[++tl]=0,f[0]=1;
38         int ans=m;
39         for(i=2;i<p;++i)if(len[i]&1)f[i]=i;
40         while(hd<=tl)
41             for(x=q[hd++],i=0;i<4;++i)
42                 if((u=ch[x][i]))
43                     q[++tl]=u,
44                     f[u]=min(f[x]+1,len[u]/2+f[strategy[u]]-len[strategy[u]]+1),
45                     ans=min(ans,f[u]+m-len[u]);
46         printf("%d\n",ans);
47     }
48     inline void insert()
49     {
50         register int i,now,cur,d,x;
51         for(n=1;n<=m;++n)
52         {
53             d=id(s[n]),cur=getfail(last);
54             if(!ch[cur][d])
55             {
56                 now=newnode(len[cur]+2),
57                 fail[now]=ch[getfail(fail[cur])][d],
58                 ch[cur][d]=now;
59                 if(len[now]<=2)strategy[now]=fail[now];
60                 else
61                 {
62                     x=strategy[cur];
63                     while(s[n-len[x]-1]!=s[n]||(len[x]+2)*2>len[now])x=fail[x];
64                     strategy[now]=ch[x][d];
65                 }
66             }
67             last=ch[cur][d];
68         }
69         work();
70     }
71     inline void intn()
72     {
73         scanf("%s",s+1),p=0,newnode(0),newnode(-1);
74         s[0]=1,m=strlen(s+1),last=0,fail[0]=1,insert();
75     }
76 }PT;
77 int main()
78 {
79     int t;scanf("%d",&t);
80     while(t--)PT.intn();
81 }

[BZOJ4044]Virus synthesis 回文自動機的DP