1. 程式人生 > >Bzoj 3654 圖樣圖森波 題解

Bzoj 3654 圖樣圖森波 題解

小寫 本質 stay cst too max 存在 href ostream

3654: 圖樣圖森破

Time Limit: 30 Sec Memory Limit: 512 MB
Submit: 123 Solved: 66
[Submit][Status][Discuss]

Description

有句老話說得好,人應該要成熟老練,也就是說不能 too simple,也不能 too young。但另外還有這麽句老話,人無論何時都應該保持單純而年輕的心態,換句話說,應該stay simple,stay young。
於是人們就疑惑了,到底應不應該聽長者的話呢?不過,不管聽還是不聽,這與本題都沒有任何關系。
長者有一個字符串集合S,此處集合的概念與數學中的集合不同,其中可以含有重復的元素。初始時 S 包含 n 個字符串 s1;s2;:::;sn。有下面兩種操作:
? 向S 中加入一個已經存在於 S 中的字符串。
? 從S 中選出兩個字符串,將這兩個字符串拼接得到的字符串加入集合 S。
長者想要知道,進行任意多次操作之後,在S 中的所有字符串中,最長的回文子串可以有多長?長者畢竟身經百戰,他發現長度可以是無窮大,這時你需要輸出Infinity。

Input

第一行含有一個整數 n,代表初始時集合的大小。
接下來的n行,每行含有一個字符串。第i行的字符串為si。保證字符串中只含有小寫英文字母。

Output

如果最長的回文子串的長度不為無窮大,則輸出一個整數,代表其長度;否則輸出Infinity。

Sample Input

3
abc
abacde
ecab

Sample Output

7

HINT

第一個樣例中,將ecab與abacde拼接,得到ecababacde,其中加粗的部分就是最長的回文子串,長度為 7。可以證明不存在更長的回文子串。第二個樣例中,可以將任意多個ha拼接起來,從而得到ha、haha、hahaha等任意奇數長度的回文子串。因此答案為無窮大,輸出Infinity。


N<=100

L<=1000

  好惡心……

  這道題貌似打法還挺多的,我就說一下記憶化搜索這種打法好了……

  我們考慮最為“正常”的答案來源,就是幾個串拼接在一起,我們嘗試從回文串的中心去向外“擴增”回文串,我們可以先枚舉每一個串的起始和末尾,因為如果想通過連接形成回文串的話必定會包括回文串的起始或末尾,我們嘗試著利用這點和記憶化搜索得到答案。我們設0為從當前點向右的串去找串的右端點進行回文匹配,1為從當前點向左的串找串的左端點進行匹配,由於1和0本質一樣,在這裏就只說0的情況了。

  我們枚舉每一個串的末尾,將它與當前字符及其右進行匹配,這裏有一點需要理解,盡管我們找的是串的末尾,但是當前點卻不一定是串的起始,它也可能是某個回文串(回文串左端點恰好是一個串的左端點)右側的第一個不匹配的點,我們找的那個串是為了將那個串拼在回文串的左側對稱的。那麽問題來了,怎麽找一個正串和一個反串的最大匹配呢?這裏就可以用一個騷操作了,我們將所有串連在一起後集體反向,組成一個大串,然後求後綴數組,再RMQ就可以做到O(1)查詢兩個串的公共子串了。

  最後我們不要忘記算單個串對於答案的貢獻,原理還是一樣,只不過改為自己和自己匹配以及自己和自己右側的匹配。

技術分享圖片
  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <cstdio>
  5 #include <algorithm>
  6 #include <cmath>
  7 #include <queue>
  8 #define N 3005
  9 #define M 100005
 10 using namespace std;
 11 int s[M*2],st[105],en[105],rnk[M*2],hi[M*2],SA[M*2],tp[M*2];
 12 int cnt[N],f[20][M*2],mn[M*2];
 13 void Rsort(int m,int n)
 14 {
 15     for(int i=0;i<=m;i++) cnt[i]=0;
 16     for(int i=1;i<=n;i++) cnt[rnk[tp[i]]]++;
 17     for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
 18     for(int i=n;i;i--) SA[cnt[rnk[tp[i]]]--]=tp[i];
 19 }
 20 bool cmp(int w,int x,int y)
 21 {
 22     return tp[x]==tp[y]&&tp[x+w]==tp[y+w];
 23 }
 24 void init(int n,int m)
 25 {
 26     for(int i=1;i<=n;i++) rnk[i]=s[i],tp[i]=i;
 27     Rsort(m,n);
 28     for(int i,w=1,p=0;p<n;m=p,w<<=1)
 29     {
 30         p=0;
 31         for(i=n-w+1;i<=n;i++) p++,tp[p]=i;
 32         for(i=1;i<=n;i++) if(SA[i]>w) p++,tp[p]=SA[i]-w;
 33         Rsort(m,n);
 34         swap(rnk,tp);
 35         rnk[SA[1]]=p=1;
 36         for(i=2;i<=n;i++) rnk[SA[i]]=cmp(w,SA[i],SA[i-1])?p:++p;
 37     }
 38     for(int i=1,k=0,j;i<=n;hi[rnk[i++]]=k)
 39         for(k=k?k-1:k,j=SA[rnk[i]-1];s[i+k]==s[j+k];k++);
 40     for(int i=1;i<=n;i++) f[0][i]=hi[i];
 41     for(int i=1;i<=18;i++)
 42     {
 43         for(int k=1;k<=n&&k+(1<<i)-1<=n;k++)
 44         {
 45             f[i][k]=(f[i-1][k]>f[i-1][k+(1<<(i-1))])?f[i-1][k+(1<<(i-1))]:f[i-1][k];
 46         }
 47     }
 48     mn[1]=0;
 49     for(int i=2;i<=n;i++)
 50     {
 51         mn[i]=mn[i-1];
 52         if(i==(1<<(mn[i]+1))) mn[i]++;
 53     }
 54 }
 55 int g[M*2][2],m,n,bel[M*2];
 56 char bb[M];
 57 bool fw[M*2][2];
 58 void inf_end()
 59 {
 60     printf("Infinity\n");
 61     exit(0);
 62 }
 63 int get_min(int x,int y)
 64 {
 65     if(x==y) return M;
 66     x=rnk[x],y=rnk[y];
 67     if(x>y) swap(x,y);
 68     x++;
 69     int k=mn[y-x+1];
 70     return min(f[k][x],f[k][y-(1<<k)+1]);
 71 }
 72 int get_lcp(int x,int y)
 73 {
 74     return min(get_min(x,n-y+1),min(en[bel[x]]-x+1,y-st[bel[y]]+1));
 75 }
 76 int dfs(int x,int op)
 77 {
 78     if(fw[x][op]) inf_end();
 79     if(g[x][op]) return g[x][op];
 80     fw[x][op]=1;
 81     if(!op)
 82     {
 83         for(int i=1;i<=m;i++)
 84         {
 85             int k=get_lcp(x,en[i]);
 86             int xx,yy;
 87             xx=x+k-1,yy=en[i]-k+1;
 88             if(xx!=en[bel[x]]&&yy!=st[i]) g[x][op]=max(g[x][op],k*2);
 89             else if(xx==en[bel[x]]&&yy==st[i]) inf_end();
 90             else if(xx==en[bel[x]]) g[x][op]=max(g[x][op],k*2+dfs(yy-1,1));
 91             else g[x][op]=max(g[x][op],k*2+dfs(xx+1,0));
 92         }
 93     }
 94     else
 95     {
 96         for(int i=1;i<=m;i++)
 97         {
 98             int k=get_lcp(st[i],x);
 99             int xx,yy;
100             xx=x-k+1,yy=st[i]+k-1;
101             if(xx!=st[bel[x]]&&yy!=en[i]) g[x][op]=max(g[x][op],k*2);
102             else if(xx==st[bel[x]]&&yy==en[i]) inf_end();
103             else if(xx==st[bel[x]]) g[x][op]=max(g[x][op],k*2+dfs(yy+1,0));
104             else g[x][op]=max(g[x][op],k*2+dfs(xx-1,1));
105         }
106     }
107     fw[x][op]=0;
108     return g[x][op];
109 }
110 int ans;
111 int main()
112 {
113     scanf("%d",&m);
114     for(int i=1;i<=m;i++)
115     {
116         scanf("%s",bb+1);
117         int len=strlen(bb+1);
118         st[i]=n+1;
119         for(int j=1;j<=len;j++)
120         {
121             n++;
122             s[n]=bb[j]-a+1;
123             bel[n]=i;
124         }
125         en[i]=n;
126     }
127     for(int i=n+1,j=n;i<=n*2;i++,j--) s[i]=s[j];
128     n<<=1;
129     init(n,26);
130     for(int i=1;i<=m;i++)
131     {
132         ans=max(ans,dfs(st[i],0));
133         ans=max(ans,dfs(en[i],1));
134     }
135     for(int i=1;i<=m;i++)
136     {
137         for(int j=st[i];j<=en[i];j++)
138         {
139             int k=get_lcp(j,j);
140             int xx=j+k-1,yy=j-k+1;
141             if(xx!=en[i]&&yy!=st[i]) ans=max(ans,k*2-1);
142             else if(xx==en[i]&&yy==st[i]) inf_end();
143             else if(xx==en[i])ans=max(ans,k*2-1+dfs(yy-1,1));
144             else ans=max(ans,k*2-1+dfs(xx+1,0));
145         }
146         for(int j=st[i];j<en[i];j++)
147         {
148             int k=get_lcp(j+1,j);
149             int xx=j-k+1,yy=j+1+k-1;
150             if(xx!=st[i]&&yy!=en[i]) ans=max(ans,k*2);
151             else if(xx==st[i]&&yy==en[i]) inf_end();
152             else if(xx==st[i])ans=max(ans,k*2+dfs(yy+1,0));
153             else ans=max(ans,k*2+dfs(xx-1,1));
154         }
155     }
156     printf("%d\n",ans);
157     return 0;
158 }
View Code

Bzoj 3654 圖樣圖森波 題解