HDOJ 4821【String】(字符串哈希、尺取法)

题目地址:HDOJ 4821【String】

• 给定一个字符串S和两个整数L和M,我们称S的一个子串是“可恢复的”,当且仅当
• (i)子串的长度为ML;
• (ii)这一子串通过串联S的M个“多样化”子串来构造:其中每个子串的长度L;而且这些子串不能有两个完全一样的串。
• 如果S的两个子串是从S的不同部分切下来的,则它们被认为是“不同的”。例如,字符串"aa"有3个不同的子串"aa",“a"和"a”。
• 请您计算S的不同的“可恢复”子字符串的数量。
• 输入
• 输入包含多个测试用例,以EOF结束。
• 每个测试用例的第一行给出两个用空格分隔的整数M和L。 • 每个测试用例的第二行给出一个字符串S,它只包含小写字母。
• S的长度不大于10^5,而且1≤M
L≤S的长度。
• 输出
• 对每个测试用例,在一行中输出答案。
• 输入样例

3 3
abcabcbcaabc

• 输出样例

2

题意:
一个字符串S 问其中有几个子串能满足以下条件:
1、长度为n*len
2、可以被分成n个len长的小串 每个串都不一样
思路:
通过字符串的hash,求出任意一个长度为L的子串的hash值。枚举字符串起始位置,从0枚举到L-1。然后,在这个位置开始,每L个字符作为一块,首先将前M块插入到map中,同时记录不相同字符串的个数,如果不相同字符串的个数是M,则满足要求。然后尺取,将这个区间向右移,删掉第1块,加入第M+1块,同样记录不相同字符串的个数。

字符串哈希 详解

代码:

#include<iostream>
#include<string.h>
#include<algorithm> 
#include<map>
using namespace std;
typedef unsigned long long ULL;
const int N = 1000010,base = 31;
char str[N];
ULL h[N],p[N],tmp;
int len,m,l,ans; 
map<ULL,int> mp;
void makehash()
{
	h[0] = 0,p[0] = 1;
	for(int i = 1;i <= len;i ++ )
	{
		h[i] = h[i-1] * base + str[i] - 'a' + 1; 
		p[i] = p[i-1] * base;
	}
}
ULL gethash(int l,int r)//获得 l 到 r 的 hash 值 
{
	return h[r] - h[l - 1] * p[r - l + 1];
}
int main()
{
	while(~scanf("%d %d",&m,&l))
	{
		scanf("%s",str + 1);
		len = strlen(str + 1);
		makehash();
		ans = 0;
		for(int i = 1;i <= l && i + m*l <= len;i++)
		{
			mp.clear();
			for(int j = i;j < i+m*l;j += l)
			{
				tmp = gethash(j,j+l-1);
				mp[tmp]++;
			}
			if(mp.size() == m) ans++;
			for(int j = i+m*l;j+l <= len+1;j += l)
			{
				tmp = gethash(j-m*l,j+l-1-m*l);
				mp[tmp]--;
				if(mp[tmp] == 0) mp.erase(tmp);
				tmp = gethash(j,j+l-1);
				mp[tmp]++;
				if(mp.size() == m) ans++;
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

温柔说给风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值