HDU4821 String(字符串哈希)

HDU4821 String(字符串哈希)

Description
Given a string S and two integers L and M, we consider a substring of S as “recoverable” if and only if
(i) It is of length M*L;
(ii) It can be constructed by concatenating M “diversified” substrings of S, where each of these substrings has length L; two strings are considered as “diversified” if they don’t have the same character for every position.
Two substrings of S are considered as “different” if they are cut from different part of S. For example, string “aa” has 3 different substrings “aa”, “a” and “a”.
Your task is to calculate the number of different “recoverable” substrings of S.
Input
The input contains multiple test cases, proceeding to the End of File.
The first line of each test case has two space-separated integers M and L.
The second ine of each test case has a string S, which consists of only lowercase letters.
The length of S is not larger than 10^5, and 1 ≤ M * L ≤ the length of S.
Output
For each test case, output the answer in a single line.
Sample Input
3 3
abcabcbcaabc
Sample Output
2

题意

给出M和L,和一个字符串S。要求找出S的子串中长度为L*M,并且可以分成M段,每段长L,并且M段都不相同的子串个数。是对每一个小子串赋予一个hash值,对于以ai开始的子串,如果他的小子串的hash值有m个不同值那么可以知道这个子串是符合要求的,ans++;那么一次枚举子串的起始位置可不可以呢?可以看出肯定不行,o(n^2)的复杂度;其实对于已经找到的一个子串,我们只需要除去他的最开头的那个小子串,加上它末尾后一个小子串,不断循环下去,就可以得到一系列的子串;因此可以把原来的串分成l个系列,每一个系列中的子串,都是可以由第一个子串减去一个小子串,加上一个新子串得到;由此降到了o(n)的复杂度;
题解转载至https://www.cnblogs.com/Norlan/p/4886383.html

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<queue>
#include<stack>
#include<vector>
#include<algorithm>
#include<functional> 
#include<map>
#include<unordered_map>
#define lowbit(x) ((x)&-(x));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e6+10,NN=2e3+10,INF=0x3f3f3f3f;
const ll MOD=1e9+7;
const ull seed=31;
unordered_map<ull,ll>mp;
ll m,l,key,len,lenstr,ans;
ull Hash[N],p[N];
char str[N];
void Hashstr(){
	Hash[0]=0;
	for(int i=1;i<=lenstr;i++) Hash[i]=Hash[i-1]*seed+str[i];
	return ;
}
void init(){
}
int main(){
	while(~scanf("%lld%lld",&m,&l)){
		scanf("%s",str+1);
		len=l*m;
		lenstr=strlen(str+1);
		Hashstr();
		p[0]=1;
		for(ll i=1;i<=l;i++) p[i]=p[i-1]*31;
		ans=0;
		for(ll i=1;i<=l&&i<=lenstr-len;i++){
			ll temp;
			bool flag=true;
			mp.clear();
			for(ll j=i;j<=i+len-l;j+=l){
				ll k=j+l-1;
				key=Hash[k]-Hash[j-1]*p[l];
				++mp[key];
			}
			if(mp.size()==m) ++ans;
			for(ll j=i+len;j<=lenstr-l+1;j+=l){//将复杂度降到O(n)的操作,自行体会
				ll k=j+l-1;
				key=Hash[k]-Hash[j-1]*p[l];
				++mp[key];
				key=Hash[k-len]-Hash[j-len-1]*p[l];
				--mp[key];
				if(!mp[key]) mp.erase(key);
				if(mp.size()==m) ++ans;
			}
		}
		printf("%lld\n",ans);
	}
        return 0;
}

猜你喜欢

转载自blog.csdn.net/Hc_Soap/article/details/107583739