HDU-4821-String-hash-map


title: HDU 4821 String --hash+map
date: 2018-10-30 10:30:03
categories: “算法”
tag:
- ACM
- map
- hash

題意:

給上限爲1e5的字符串,找出有多少長度爲M*L的子串,並且該子串的M個長度爲L的子串各不相同。

思路:

開始認爲子串不想同的定義是每個位置的字符不相同,感覺說的有歧義。

two strings are considered as “diversified” if they don’t have the same character for every position.

最暴力的算法就是枚舉所有長度爲M*L的子串,判斷hash子串是否合格。但是枚舉子串是n^2的時間複雜度。可以仔細想一下,我們可以從下標1~L枚舉起點,然後以這個起點用指針每次跳L步長。然後跟尺取原理似的一直保持map裏的元素是M個。這樣時間複雜度是O(L*n/L),即O(n)。爲什麼用map去重而不用set,原因就是對於相同的我們記住它出現了幾次,只有他出現的次數==0的時候纔將它刪去。

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N=1e5+10;

ull base[N], _hash[N], mul=37;
char str[N];

inline ull hash_str(int l, int r){
    return _hash[r]-_hash[l-1]*base[r-l+1];
}

int main(){
    int M, L;
    while(~scanf("%d%d", &M, &L)){
        scanf("%s", str+1);
        int len=strlen(str+1);
        base[0]=1;
        _hash[0]=0;
        for(int i=1; i<=len; i++){
            base[i]=base[i-1]*mul;
            _hash[i]=_hash[i-1]*mul+str[i];
        }
        map<ull, int> mp;

        int ans=0;
        for(int i=1; i<=L; i++){//enum start point
            mp.clear();

            for(int j=i; i+M*L-1<=len && j+L-1<=len; j+=L){
                if(j-M*L>=i){
                    ull tmp=hash_str(j-M*L, j-M*L+L-1);
                    mp[tmp]--;
                    if(mp[tmp]==0) mp.erase(tmp);
                }
                mp[hash_str(j, j+L-1)]++;
                if(mp.size()==M) ans++;
            }
        }

        printf("%d\n", ans);

    }

    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章