zoukankan      html  css  js  c++  java
  • 牛客练习赛61 相似的子串(二分+Hash)

    题面在此

    题解:将字符串分成k部分,然后求最长前缀,所以我们只关注前缀部分就好了,公共前缀后边的是啥不用管,那么问题就转化成了是否存在k个不相交的字符串的最长公共前缀问题。首先用Hash来记录一下字符串,然后再二分枚举最长前缀的长度。怎么样才能保证不相交呢?可以用map记录一段字符串的右边界。然后当这个串再次出现时,判断当前的左边界和上次的右边界时候相交。。这里要用无序map,否则会T,也可以用ull对Hash自动取余。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll N=2e5+7;
    char s[N];
    ll Hash[N],p[N];
    ll mod=1e9+9;
    ll base=127;
    ll n,m;
    unordered_map<ll ,ll >mp1,mp2;
    ll getHash(ll x,ll y){
        return (Hash[y]%mod-Hash[x-1]*p[y-x+1]%mod+mod)%mod;
    }
    bool check(ll x){
        mp1.clear();mp2.clear();
        for(int i=x;i<=n;i++){
            ll tmp=getHash(i-x+1,i); 
            if(mp1[tmp]==0) {
                mp1[tmp]=i;
                mp2[tmp]++;
            }
            else if(mp1[tmp]<=i-x) {
                mp1[tmp]=i;mp2[tmp]++;
            }
            if(mp2[tmp]>=m) return 1;
        }
        return 0;
    }
    int main(){
        cin>>n>>m;
        scanf("%s",s+1);
        p[0]=1;
        for(ll i=1;i<=n;i++){
            Hash[i]=((Hash[i-1]*base)%mod+s[i]-'a')%mod;
            p[i]=p[i-1]*base%mod;
        }
        ll ans=0;
        ll l=1,r=n;
        while(l<=r){
            ll mid=(l+r)/2;
            if(check(mid)){
                ans=max(ans,mid);
                l=mid+1;
            }
            else r=mid-1;
        }
        cout<<ans<<endl;    
        return 0;
    }
  • 相关阅读:
    百度地图(8)-图层
    百度地图(7)-点聚合
    百度地图(6)-信息窗口
    鸟哥学习笔记二(基础篇第七章)
    鸟哥学习笔记一(基础篇第六章)
    sql server学习笔记二
    sql server学习笔记一
    centos下sudo命令不能使用
    CentOS系统时间与现在时间相差8小时解决方法
    SUID GUID详解
  • 原文地址:https://www.cnblogs.com/Accepting/p/12686222.html
Copyright © 2011-2022 走看看