字符串hash

匿名 (未验证) 提交于 2019-12-02 23:52:01

选用 BKDRhash 方式
参考资料:https://www.byvoid.com/blog/string-hash-compare/
字符串通篇资料:https://blog.csdn.net/ck_boss/article/details/47066727

HDU 4821 string

传送门:https://vjudge.net/problem/HDU-4821
题意:给出M和L,和一个字符串S。要求找出S的子串中长度为L*M,并且可以分成M段,每段长L,并且M段都不相同的子串个数。

思路:一道字符串哈希题。哈希的方法是BKDRHash,哈希中进制是31,131等素数。

	#include <iostream> #include <map> #include <string> #include <cstring> #include <cstdio> #define maxn 100005 #define SEED 31 #define ULL unsigned long long using namespace std;  ULL k[maxn],ha[maxn]; map <ULL , int> mp; int m,l; char s[maxn]; int main(){ 	while (scanf("%d%d",&m,&l)!=EOF){ 		scanf("%s",s); 		k[0]=1; 		int len = strlen(s); 		ha[len] = 0; 		for (int i=1;i<=l;i++) 			k[i] = k[i-1]*SEED; 		for (int i=len-1;i>=0;i--) 			ha[i] = ha[i+1]*SEED + s[i] - 'a' + 1; 		int ans=0;  		for (int i=0;i<l && i+m*l<len;i++){ 			mp.clear(); 			for (int j=i;j<i+m*l;j+=l) 				mp[ha[j]-ha[j+l]*k[l]]++; 			if (mp.size() == m) ans++; 			for (int j=i+m*l;j<=len-l;j+=l){ 				int head = j-m*l; 				ULL x = ha[head] - ha[head+l]*k[l]; 				mp[x]--; 				if (mp[x] == 0) mp.erase(x); 				mp[ha[j] - ha[j+l]*k[l]]++; 				if (mp.size() == m) ans ++; 			} 		} 		cout << ans << endl; 	} } 

HDU 4080 Stammering Aliens
题意
每组数据为一个整数m和一个长度不小于m的字符串,求该字符串的一个子串,该子串在满足出现次数不小于m的同时应尽量长。
输出该长度和最右侧出现的起始位置。如果存在多组数据,输出有最靠近右侧的那组。
m<=4e5,时限5s


字符串hash+二分答案。我写的版本被卡了,从网上找了一个相同写法的4000ms卡过去了,学习一下。
by Vicente:

#include <cstring> #include <iostream> #include <map> #define maxn 40005 #define SEED 31 #define ULL unsigned long long  using namespace std; int m,len; ULL k[maxn],ha[maxn]; char s[maxn]; map <ULL , int> mp;  bool isOK(int L){ 	mp.clear(); 	for (int i=0;i+L<=len;i++){ 		mp[ha[i]-ha[i+L]*k[L]]++; 		if (mp[ha[i] - ha[i+L]*k[L]]>=m)return true;  	} 	return false; } int main(){ 	while (scanf("%d",&m) &&  m!=0){ 		scanf("%s",s); 		len = strlen(s); 		k[0] = 1; 		for (int i=1;i<=len;i++) k[i] = k[i-1] * SEED; 		ha[len] = 0; 		for (int i = len-1;i>=0;i--) ha[i] = ha[i+1] * SEED + s[i] - 'a'+1; 		int l=m,r=len,mid; 		while (l<r){ 			mid = (l+r+1) >>1; 			if (isOK(mid)) l = mid;else r=mid-1; 		}  		if (!isOK(r)) { 			puts("none"); 			continue; 		}else{ 			cout << r << " "; 			mp.clear(); 			for (int i=0;i+r<=len;i++){ 				mp[ha[i]-ha[i+r]*k[r]]++; 				if (mp[ha[i] - ha[i+r]*k[r]]>=m) cout << i << endl;  			} 		} 	} } 

AC版本:

#include <cstring> #include <iostream> #include <map> #define ull unsigned long long using namespace std; const int maxn = (int)4e4 + 10; int n,len; char s[maxn]; ull has[maxn]; ull p = 2333,a[maxn];   bool judge(int x) { 	map<int,int> mp; 	ull res; 	for (int i = 1;i + x - 1 <= len;i ++) 	{ 		res = has[i + x - 1] - has[i - 1] * a[x]; 		if (++mp[res] >= n) return 1; 	} 	return 0; } int check(int x) { 	map<int,int> mp; 	int pos = -1; 	ull res; 	for (int i = 1;i + x - 1 <= len;i ++) 	{ 		res = has[i + x - 1] - has[i - 1] * a[x]; 		if (++mp[res] >= n) pos = i; 	} 	return pos - 1; } int main() { 	while (~scanf("%d",&n) && n) 	{ 		scanf("%s",s + 1); 		len = strlen(s + 1); 		has[0] = 0,a[0] = 1; 		for (int i = 1;i <= len;i ++) 		{ 			has[i] = has[i - 1] * p + s[i]; 			a[i] = a[i - 1] * p; 		} 		int l = 1,r = len + 1,mid; 		while (l <= r) 		{ 			mid = (l + r) >> 1; 			if (judge(mid)) l = mid + 1; 			else r = mid - 1; 		} 		if (r == 0) 			printf("none\n"); 		else 			printf("%d %d\n",r,check(r)); 	} 	return 0;	 }  

哈哈哈经过学习,我改了一点内容,终于也把这道题卡过去了。

4773ms…说是卡过去真是一点不错。
AC代码 by Vicente.

#include <cstring> #include <iostream> #include <map> #define maxn 40005 #define SEED 31 #define ULL unsigned long long  using namespace std; int m,len; ULL k[maxn],ha[maxn]; char s[maxn]; map <ULL , int> mp;  bool isOK(int L){ 	mp.clear(); 	ULL res; 	for (int i=0;i+L<=len;i++){ 		res=ha[i]-ha[i+L]*k[L]; 		 		if (++mp[res]>=m)return true;  	} 	return false; }  int main(){ 	while (scanf("%d",&m) &&  m!=0){ 		scanf("%s",s); 		len = strlen(s); 		k[0] = 1; 		ha[len] = 0; 		for (int i=1;i<=len;i++)//强行放在一起写,就没爆T了 			k[i] = k[i-1] * SEED,ha[len-i] = ha[len-i+1] * SEED + s[len-i] - 'a'+1;; 		// for (int i = len-1;i>=0;i--) ha[i] = ha[i+1] * SEED + s[i] - 'a'+1; 		int l=1,r=len+1,mid;  		while (l<=r){ 			mid = (l+r) >>1; 			if (isOK(mid)) l = mid+1;else r=mid-1; 		}  		if (r == 0) { 			puts("none"); 			continue; 		}else{ 			cout << r << " "; 			mp.clear(); 			int x; 			for (int i=0;i+r<=len;i++){ 				mp[ha[i]-ha[i+r]*k[r]]++; 				if (mp[ha[i] - ha[i+r]*k[r]]>=m) x=i;//cout << i << endl;  			} 			cout << x << endl;//不用x标记的话会WA,原因自己想 		} 	} } 
文章来源: https://blog.csdn.net/qq_42447015/article/details/97242753
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!