HDU4821. String(Hash)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4821
https://acm.njupt.edu.cn/problem/HDU4821
在这里插入图片描述在这里插入图片描述
题意:从一个字符串中分割出M个长度为L的子字符串,并且这些子字符串不相同(Hash值不同).
解题思路:
一开始我是直接暴力,从i开始,尺取法每次截取M个长度为L的字段,结果超时了。
后来看到别人的题解,对for循环进行了修改,i从1遍历到L,然后在循环里再进行删除第一个L长度,在后面加上一个L长度,(删头添尾)直到不能再加L的时候。
至于如何比较M个子串Hash不同,直接用一个map类型或者set类型进行统计数目就行。注意map类型时,如果m[i]==0,记得要用m.erase(i)将i删除。

#include<iostream>
#include<cstdio>
#include<string>
#include<string.h>
#include<set>
#include<map>
using namespace std;
#define ll unsigned long long
const int mod=1e9+7;
const int p=31;
ll Hash[110000];
ll Pow[110000];
char s[110000];
map<ll,int> m;
int M,L;
int len;
int ans;
void get_hash()
{
	Hash[1]=s[1]-'a'+1;
	for(int i=2;i<=len;i++)
		Hash[i]=(Hash[i-1]*p+(s[i]-'a'+1))%mod;
}
ll cmp_hash(int l,int r)
{
	return (Hash[r]+mod-Hash[l-1]*Pow[r-l+1]%mod)%mod;
}
int main()
{
	Pow[0]=1;
	for(int i=1;i<=100000;i++)
		Pow[i]=Pow[i-1]*p%mod;
	while(scanf("%d%d",&M,&L)!=EOF)
	{
		m.clear();
		memset(Hash,0,sizeof(Hash));
		ans=0;
	    scanf("%s",s+1);
	    len=strlen(s+1);
	    get_hash();
	    for(int i=1;i<=L&&i<=len-M*L+1;i++)
	    {
		   m.clear();
		   int cnt=0;
		   for(int j=i;j<=i+M*L-1;j+=L)
		   {
			  m[cmp_hash(j,j+L-1)]++;
		   }
		   if(m.size()==M)
			   ans++;
		   for(int j=i+M*L;j+L-1<=len;j+=L)
		   {
			   ll t1=cmp_hash(j,j+L-1);
			   ll t2=cmp_hash(j-M*L,j-M*L+L-1);
			   m[t2]--;
			   m[t1]++;
			   if(m[t2]==0)
				   m.erase(t2);
			   if(m.size()==M)
				   ans++;
		   }
	     }
	     cout<<ans<<endl;
	}
	return 0;
}
原创文章 65 获赞 3 访问量 2109

猜你喜欢

转载自blog.csdn.net/littlegoldgold/article/details/104877191
今日推荐