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;
    }
  • 相关阅读:
    POJ 2251 Dungeon Master
    HDU 3085 Nightmare Ⅱ
    CodeForces 1060 B Maximum Sum of Digits
    HDU 1166 敌兵布阵(树状数组)
    HDOJ 2050 折线分割平面
    HDU 5879 Cure
    HDU 1878 欧拉回路
    HDU 6225 Little Boxes
    ZOJ 2971 Give Me the Number
    HDU 2680 Choose the best route
  • 原文地址:https://www.cnblogs.com/Accepting/p/12686222.html
Copyright © 2011-2022 走看看