生活随笔
收集整理的这篇文章主要介绍了
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(二分+后缀数组)的全部内容,希望文章能够帮你解决所遇到的问题。
如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。