牛客练习赛61 相似的子串(二分+Hash)
2024-10-08 22:46:16
题解:将字符串分成k部分,然后求最长前缀,所以我们只关注前缀部分就好了,公共前缀后边的是啥不用管,那么问题就转化成了是否存在k个不相交的字符串的最长公共前缀问题。首先用Hash来记录一下字符串,然后再二分枚举最长前缀的长度。怎么样才能保证不相交呢?可以用map记录一段字符串的右边界。然后当这个串再次出现时,判断当前的左边界和上次的右边界时候相交。。这里要用无序map,否则会T,也可以用ull对Hash自动取余。
code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=2e5+;
char s[N];
ll Hash[N],p[N];
ll mod=1e9+;
ll base=;
ll n,m;
unordered_map<ll ,ll >mp1,mp2;
ll getHash(ll x,ll y){
return (Hash[y]%mod-Hash[x-]*p[y-x+]%mod+mod)%mod;
}
bool check(ll x){
mp1.clear();mp2.clear();
for(int i=x;i<=n;i++){
ll tmp=getHash(i-x+,i);
if(mp1[tmp]==) {
mp1[tmp]=i;
mp2[tmp]++;
}
else if(mp1[tmp]<=i-x) {
mp1[tmp]=i;mp2[tmp]++;
}
if(mp2[tmp]>=m) return ;
}
return ;
}
int main(){
cin>>n>>m;
scanf("%s",s+);
p[]=;
for(ll i=;i<=n;i++){
Hash[i]=((Hash[i-]*base)%mod+s[i]-'a')%mod;
p[i]=p[i-]*base%mod;
}
ll ans=;
ll l=,r=n;
while(l<=r){
ll mid=(l+r)/;
if(check(mid)){
ans=max(ans,mid);
l=mid+;
}
else r=mid-;
}
cout<<ans<<endl;
return ;
}
最新文章
- $\LaTeX$笔记:首字下沉
- Android Studio 2.2的新鲜事
- 《oracle每天一练》触发器不能调用或间接调用COMMIT,ROLLBACK等DCL语句
- linux read简单用法
- 3D Touch集成过程整理
- 课堂笔记--Strom并发模型
- 创建泛类集合List以及数组转集合,集合转数组的应用
- nyoj 93 汉诺塔(三)
- Android--数据持久化之内部存储、Sdcard存储
- 使用ASP.NET操作IIS7中使用应用程序
- 深层次详解Exception
- 捕获JSON 解析错误
- Maven3.0 服务器配置搭建
- Oracle EBS-SQL (PO-4):检查采购订单明细.sql
- OWC11生成统计图案例
- 一篇文章带你了解Cloud Native
- 每日分享!~ JavaScript(拖拽事件)
- 判断 Python 版本
- 干货分享:让你分分钟学会 javascript 闭包(转)
- CSS(三)