【二分+字符串hs】[POI2000] 公共串

题目描述
给出几个由小写字母构成的单词,求它们最长的公共子串的长度。 任务:

l 读入单词

l 计算最长公共子串的长度

l 输出结果

输入格式
文件的第一行是整数 n,1<=n<=5,表示单词的数量。接下来n行每行一个单词,只由小写字母组成,单词的长度至少为1,最大为2000。

输出格式
仅一行,一个整数,最长公共子串的长度。

样例一
input

3
abcb
bca
acbc 
output

2
限制与约定
时间限制:1s1s
空间限制:256MB
T

这道题看起来十分复杂,其实就是暴力二分长度

然后在第一个串中框一个这么长的串去其他的里面去验证

代码在此

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define MA 2011
 5 #define seed 1313131
 6 using namespace std;
 7 typedef unsigned long long ull;
 8 int n,l=1,r=0x7f7f7f7f,ans;
 9 char in[10][MA];
10 int len[10];
11 ull vv[10][MA],se[MA];
12 inline bool check(int lenn)
13 {
14     for(int i=1;i+lenn-1<=len[1];i++)
15     {
16         int l=i,r=i+lenn-1;
17          int yeah=0;
18         ull val=vv[1][r]-vv[1][l-1]*se[lenn];
19         for(int j=2;j<=n;j++)
20         {
21             int kk=0;
22             for(int k=1;k+lenn-1<=len[j];k++)
23             {
24                 int ll=k,rr=k+lenn-1;
25                 if(val==vv[j][rr]-vv[j][ll-1]*se[lenn]){kk=1;break;}
26             }
27             if(kk)yeah++;
28         }
29         if(yeah==n-1)return 1;
30     }
31     return 0;
32 }
33 int main()
34 {
35     scanf("%d",&n);    
36     se[0]=1;
37     for(int i=1;i<MA;i++)se[i]=se[i-1]*seed;
38     for(int i=1;i<=n;i++)
39     {
40         scanf("%s",in[i]+1);
41         int ll=strlen(in[i]+1);
42         len[i]=ll,r=min(r,ll);
43         for(int j=1;j<=len[i];j++)
44             vv[i][j]=vv[i][j-1]*seed+in[i][j];
45     }
46     while(l<=r)
47     {
48         int mid=(l+r)/2;
49         if(check(mid))l=mid+1,ans=mid;
50         else r=mid-1;
51     }
52     printf("%d\n",ans);
53 }
54 /*
55 4
56 alamakotaipsa
57 olamakotaikure
58 kotaipsa
59 ewamaswinkekotaipsa
60 */

 

posted @ 2019-01-01 11:06  浅夜_MISAKI  阅读(235)  评论(0编辑  收藏  举报