题意
给你m,l求一个字符串,他的字串长度是m*l,并且这个子串要满足是由m个l长的不同字符串组成,求这样的子串有几个
思路
给定长度的字符串,可以用尺取法降低复杂度,我们先把每个的l长hash值求出,然后用尺取,每次前面删掉一个l长的并在末尾加上一个l长的判断是不是等于m。尺取注意边界。
#include <iostream>
#include <cstdio>
#include <map>
#include <cstring>
using namespace std;
const int MAXN=1e5+10;
typedef unsigned long long ull;
const int seed=13331;
ull hash_1[MAXN],xp[MAXN];
char str[MAXN];
ull ans[MAXN];
void init()
{
xp[0]=1;
for(int i=1;i<MAXN;i++) xp[i]=xp[i-1]*seed;
}
int make_hash()
{
int len=strlen(str);
hash_1[len]=0;
for(int i=len-1;i>=0;i--)
hash_1[i]=hash_1[i+1]*seed+str[i]-'a'+1;
return len;
}
ull get_hash(int i,int l)
{
return hash_1[i]-hash_1[i+l]*xp[l];
}
map<ull,int> mp;
int main()
{
int m,l;
init();
while(scanf("%d%d",&m,&l)!=EOF)
{
scanf("%s",str);
int len=make_hash();
int cont=0;
for(int i=0;i<=len-l;i++)
ans[cont++]=get_hash(i,l);
int ans1=0;
for(int i=0;i<l&&i+l<=len;i++)
{
mp.clear();
int k=0;
for(int j=i;j<i+m*l;j+=l)
{
if(mp[ans[j]]==0) k++;
mp[ans[j]]++;
}
if(k==m) ans1++;
for(int j=i;j+m*l+l<=len;j+=l)
{
mp[ans[j]]--;
if(mp[ans[j]]==0) k--;
if(mp[ans[j+m*l]]==0) k++;
mp[ans[j+m*l]]++;
if(k==m) ans1++;
}
}
printf("%d\n",ans1);
}
return 0;
}