BZOJ2946 [Poi2000]公共串 二分+hash
2017-12-30 22:09
344 查看
给出几个由小写字母构成的单词,求它们最长的公共子串的长度。n<=5,maxlen<=2000.
预处理出每个串的哈希值
二分答案len,前4个串的所有长为len的子串全部用map存,再最后一个串跑,看是否在前面全部出现.
常数略大,但是数据比较小没问题
#include <bits/stdc++.h>
#define ull unsigned long long
#define clr(x,i) memset(x,i,sizeof(x))
using namespace std;
const int N=2005;
const ull seed=173;
char str[6]
;
int n,len[6],a[6]
;
ull h[6]
,pw
;
map<int,ull> mp[6];
inline ull geth(int k,int l,int r)
{
return h[k][r]-h[k][l-1]*pw[r-l+1];
}
bool check(int now)
{
for(int i=1;i<=n;i++)
mp[i].clear();
for(int i=1;i<n;i++)
{
for(int j=1;j+now-1<=len[i];j++){
ull ret=geth(i,j,j+now-1);
mp[i][ret]=1;
}
}
for(int i=1;i+now-1<=len
;i++)
{
ull x=geth(n,i,i+now-1);
bool flag=1;
for(int j=1;j<n;j++)
if(!mp[j][x])flag=0;
if(flag)return true;
}
return false;
}
void solve()
{
int l=1,r=len[1],mid,ans=0;
for(int i=1;i<=n;i++)r=max(r,len[i]);
while(l<=r)
{
mid=(l+r)>>1;
if(check(mid))
ans=mid,l=mid+1;
else
r=mid-1;
}
printf("%d",ans);
}
int main()
{
scanf("%d",&n);
if(n==1){
printf("0");return 0;
}
for(int i=1;i<=n;i++){
scanf("%s",str[i]+1);len[i]=strlen(str[i]+1);
for(int j=1;j<=len[i];j++)
a[i][j]=str[i][j]-'a'+1;
}
pw[0]=1;
for(int i=1;i<=2000;i++)pw[i]=pw[i-1]*seed;
for(int i=1;i<=n;i++)
for(int j=1;j<=len[i];j++)
h[i][j]=h[i][j-1]*seed+a[i][j];
solve();
return 0;
}
这个好像是后缀自动机的模板题,以后来补。。
预处理出每个串的哈希值
二分答案len,前4个串的所有长为len的子串全部用map存,再最后一个串跑,看是否在前面全部出现.
常数略大,但是数据比较小没问题
#include <bits/stdc++.h>
#define ull unsigned long long
#define clr(x,i) memset(x,i,sizeof(x))
using namespace std;
const int N=2005;
const ull seed=173;
char str[6]
;
int n,len[6],a[6]
;
ull h[6]
,pw
;
map<int,ull> mp[6];
inline ull geth(int k,int l,int r)
{
return h[k][r]-h[k][l-1]*pw[r-l+1];
}
bool check(int now)
{
for(int i=1;i<=n;i++)
mp[i].clear();
for(int i=1;i<n;i++)
{
for(int j=1;j+now-1<=len[i];j++){
ull ret=geth(i,j,j+now-1);
mp[i][ret]=1;
}
}
for(int i=1;i+now-1<=len
;i++)
{
ull x=geth(n,i,i+now-1);
bool flag=1;
for(int j=1;j<n;j++)
if(!mp[j][x])flag=0;
if(flag)return true;
}
return false;
}
void solve()
{
int l=1,r=len[1],mid,ans=0;
for(int i=1;i<=n;i++)r=max(r,len[i]);
while(l<=r)
{
mid=(l+r)>>1;
if(check(mid))
ans=mid,l=mid+1;
else
r=mid-1;
}
printf("%d",ans);
}
int main()
{
scanf("%d",&n);
if(n==1){
printf("0");return 0;
}
for(int i=1;i<=n;i++){
scanf("%s",str[i]+1);len[i]=strlen(str[i]+1);
for(int j=1;j<=len[i];j++)
a[i][j]=str[i][j]-'a'+1;
}
pw[0]=1;
for(int i=1;i<=2000;i++)pw[i]=pw[i-1]*seed;
for(int i=1;i<=n;i++)
for(int j=1;j<=len[i];j++)
h[i][j]=h[i][j-1]*seed+a[i][j];
solve();
return 0;
}
这个好像是后缀自动机的模板题,以后来补。。
相关文章推荐
- 【二分答案+智障的字符串hash】BZOJ2946-[Poi2000]公共串(Ranklist倒一达成!!!!!)【含hash知识点】
- 【二分答案】【哈希表】【字符串哈希】bzoj2946 [Poi2000]公共串
- 2946: [Poi2000]公共串 (hash+二分)
- BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案
- 2946: [Poi2000]公共串 二分+hash
- 【BZOJ】【2946】【POI2000】公共串
- 【bzoj2946】[Poi2000]公共串
- bzoj 2946: [Poi2000]公共串 后缀自动机
- 【BZOJ 2946】【POI 2000】公共串【后缀数组】【裸】
- BZOJ 2946: [Poi2000]公共串( 后缀自动机 )
- BZOJ2946: [Poi2000]公共串
- [BZOJ2946][Poi2000]公共串 && 后缀自动机
- BZOJ 2946: [Poi2000]公共串
- [BZOJ2946][POI2000]公共串(后缀自动机)
- BZOJ 2946 [Poi2000]公共串 后缀自动机
- [BZOJ2946][Poi2000]公共串(后缀自动机)
- [BZOJ2946] [Poi2000]公共串解题报告|后缀数组
- 【BZOJ 2946】 2946: [Poi2000]公共串 (SAM)
- 【bzoj2946】[Poi2000]公共串
- bzoj2946 [Poi2000]公共串(后缀数组 || 后缀自动机)