题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4821
题意:给出M和L的值,字符串s,求其中满足条件的M*L长度子串个数(条件:可分为M个长度为L各不相同的子串)
我们使用哈希函数,有一个长为M*L的窗口滑动,对每个遇到的L的子串求哈希值,比较是否就放入map中判断是否有重复,前M个判断好了,下一步就将第M+1个放入map,前第M个提出,每次满足条件就++,最后输出结果
这位博主的题解写的挺好的,顺便发一下:https://www.cnblogs.com/tigerisland/p/7564689.html
ac代码如下:
#include<cstdio>
#include<iostream>
#include<map>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 100100
typedef unsigned long long int ull;
typedef long long ll;
char str[maxn];
ll xp[maxn];
ll hash1[maxn];
ll base = 175;
map<ll, int>mp;
void init()
{
xp[0] = 1;
for (int i = 1; i < maxn; i++)
xp[i] = xp[i - 1] * base;
}
ll get_hash(int i, int L)
{
return hash1[i + L - 1] - hash1[i - 1] * xp[L];
}
int main()
{
int M, L;
init();
while (scanf("%d%d",&M,&L)!=EOF)
{
scanf("%s", str + 1);
ll len = strlen(str + 1);
hash1[0] = 0;
for (ll i = 1; i <= len; i++)
{
hash1[i] = hash1[i - 1] * base + (str[i] - 'a'+1);
}
ll ans = 0;
for (ll i = 1; i <= L; i++)
{
mp.clear();
ll cnt = 0;
// i + j*L <--->i + (j + 1)*L - 1
for (ll j = 0; i + (j + 1) * L - 1 <= len; j++)
{
cnt++;
ull tmp = get_hash(i + j*L,L);
mp[tmp]++;
if (cnt >= M)
{
if (cnt > M)
{
ll tmp1 = get_hash(i + (j - M)*L, L);//前第M个
if (mp[tmp1])
{
mp[tmp1]--;
if(mp[tmp1]==0)mp.erase(tmp1);//可能中间有重复
}
}
if (mp.size() == M)ans++;
}
}
}
printf("%d\n", ans);
}
return 0;
}