生活随笔
收集整理的這篇文章主要介紹了
POJ1226 Substrings(二分+后缀数组)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題意:給n個字符串,求最長的子串,滿足它或它的逆置出現在所有的n個字符串中。
- 把n個字符串及其它們的逆置拼接,中間用不同字符隔開,并記錄suffix(i)是屬于哪個字符串的;
- 跑后綴數組計算height;
- 二分答案,height分組,看組里面是否都包含了n個字符串的后綴;
- 注意n=1的情況。。
1 #include<cstdio>
2 #include<cstring>
3 #include<cmath>
4 #include<algorithm>
5 using namespace std;
6 #define MAXN 22222
7 int wa[MAXN],wb[MAXN],wv[MAXN],ws[MAXN];
8 int cmp(
int *r,
int a,
int b,
int l){
9 return r[a]==r[b] && r[a+l]==r[b+
l];
10 }
11 int sa[MAXN],rank[MAXN],height[MAXN];
12 void SA(
int *r,
int n,
int m){
13 int *x=wa,*y=
wb;
14
15 for(
int i=
0; i<m; ++i) ws[i]=
0;
16 for(
int i=
0; i<n; ++i) ++ws[x[i]=
r[i]];
17 for(
int i=
1; i<m; ++i) ws[i]+=ws[i-
1];
18 for(
int i=n-
1; i>=
0; --i) sa[--ws[x[i]]]=
i;
19
20 int p=
1;
21 for(
int j=
1; p<n; j<<=
1,m=
p){
22 p=
0;
23 for(
int i=n-j; i<n; ++i) y[p++]=
i;
24 for(
int i=
0; i<n; ++i)
if(sa[i]>=j) y[p++]=sa[i]-
j;
25 for(
int i=
0; i<n; ++i) wv[i]=
x[y[i]];
26 for(
int i=
0; i<m; ++i) ws[i]=
0;
27 for(
int i=
0; i<n; ++i) ++
ws[wv[i]];
28 for(
int i=
1; i<m; ++i) ws[i]+=ws[i-
1];
29 for(
int i=n-
1; i>=
0; --i) sa[--ws[wv[i]]]=
y[i];
30 swap(x,y); x[sa[
0]]=
0; p=
1;
31 for(
int i=
1; i<n; ++i) x[sa[i]]=cmp(y,sa[i-
1],sa[i],j)?p-
1:p++
;
32 }
33
34 for(
int i=
1; i<n; ++i) rank[sa[i]]=
i;
35 int k=
0;
36 for(
int i=
0; i<n-
1; height[rank[i++]]=
k){
37 if(k) --
k;
38 for(
int j=sa[rank[i]-
1]; r[i+k]==r[j+k]; ++
k);
39 }
40 }
41
42 int sn,n,r[MAXN],belong[MAXN];
43 bool isok(
int len){
44 bool vis[
111]={
0};
int cnt=
0;
45 for(
int i=
2; i<=n; ++
i){
46 if(height[i]>=
len){
47 if(!
vis[belong[sa[i]]]){
48 vis[belong[sa[i]]]=
1;
49 ++
cnt;
50 }
51 if(!vis[belong[sa[i-
1]]]){
52 vis[belong[sa[i-
1]]]=
1;
53 ++
cnt;
54 }
55 if(cnt==sn)
return 1;
56 }
else{
57 if(cnt==sn)
return 1;
58 memset(vis,
0,
sizeof(vis));
59 cnt=
0;
60 }
61 }
62 return 0;
63 }
64 int main(){
65 char str[
111];
66 int t;
67 scanf(
"%d",&
t);
68 while(t--
){
69 n=
0;
70 scanf(
"%d",&
sn);
71 for(
int i=
0; i<sn; ++
i){
72 scanf(
"%s",str);
73 if(sn==
1){
74 printf(
"%d\n",strlen(str));
75 break;
76 }
77 for(
int j=
0; str[j]; ++
j){
78 belong[n]=
i;
79 r[n++]=
str[j];
80 }
81 r[n++]=
127+(i<<
1);
82 for(
int j=strlen(str)-
1; j>=
0; --
j){
83 belong[n]=
i;
84 r[n++]=
str[j];
85 }
86 r[n++]=
127+(i<<
1|
1);
87 }
88 if(sn==
1)
continue;
89 r[--n]=
0;
90 SA(r,n+
1,
333);
91 int l=
0,r=
100;
92 while(l<
r){
93 int mid=l+r+
1>>
1;
94 if(isok(mid)) l=
mid;
95 else r=mid-
1;
96 }
97 printf(
"%d\n",l);
98 }
99 return 0;
100 }
?
轉載于:https://www.cnblogs.com/WABoss/p/5225007.html
總結
以上是生活随笔為你收集整理的POJ1226 Substrings(二分+后缀数组)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。