zoukankan      html  css  js  c++  java
  • hdoj4821(字符串hash+map判重)

    题目链接:https://vjudge.net/contest/362409#problem/I

    题意:给定一个字符串s,求有多少子串,满足长度为M*L,且由M个不同的子串(长度均为L)组成。


    思路:
      先用hs[i]记录前i个字符的hash值,然后利用hs[r]-hs[l-1]*base[r-l+1]得到子串[l,r]的hash值。(自然溢出可AC,模1e18的质数过不了)

      利用上面的方法可以O(1)得到子串[l,r]的hash值。然后就是遍历,以i(1<=i<=L)为起点,将i后面的M个长度为L的子串放进map里判重,然后通过删除第一个,添加后面一个来移动。删除时如果map值为0,要将其从map中删除。复杂度为O(L*n/L)=O(n)。

    AC code:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<tr1/unordered_map>
    using namespace std;
    using namespace tr1;
    
    typedef unsigned long long ull;
    const int maxn=1e5+5;
    int n,M,L,ans;
    char s[maxn];
    ull base=131,bs[maxn],hs[maxn];
    unordered_map<ull,int> mp;
    
    ull gethash(int l,int r){
        return (hs[r]-hs[l-1]*bs[r-l+1]);
    }
    
    void init(){
        bs[0]=1;
        for(int i=1;i<maxn;++i)
            bs[i]=bs[i-1]*base;
    }
    
    int main(){
        init();
        while(~scanf("%d%d",&M,&L)){
            scanf("%s",s+1);
            n=strlen(s+1);
            ans=0;
            hs[0]=0;
            for(int i=1;i<=n;++i)
                hs[i]=(hs[i-1]*base+s[i]);
            for(int i=1;i<=L;++i){
                mp.clear();
                int p=i,num=0;
                while(p+L<=n+1){
                    ull t1=gethash(p,p+L-1);
                    ++mp[t1];
                    ++num;
                    if(num==M) break;
                    p+=L;
                }
                if(num!=M) break;
                if(mp.size()==M) ++ans;
                p+=L;
                while(p+L<=n+1){
                    ull t2=gethash(p-M*L,p-M*L+L-1);
                    ull t3=gethash(p,p+L-1);
                    ++mp[t3];
                    --mp[t2];
                    if(mp[t2]==0) mp.erase(t2);    
                    if(mp.size()==M) ++ans;
                    p+=L;
                }
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    前端基础进阶变量对象详解
    伪元素::before与::after的用法
    网站性能优化你需知道的东西
    Python爬虫音频数据
    python一步高级编程
    Android APK打包流程
    软件漏洞学习
    pycrypto 安装
    ubuntu16.04中将python3设置为默认
    Android NDK 编译选项设置[zhuan]
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/12502321.html
Copyright © 2011-2022 走看看