HDU-4821-String-hash-map
阿新 • • 發佈:2018-11-05
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; }