題意:
給出m和L和一個字符串s,要求在s中找到一種子串,滿足長度爲m*l,且分成m段長度爲l的小子串可以使得任意兩個小子串不完全相同,問一共有多少個這樣的子串。
思路:
字符串哈希。
預處理出每個長度爲L的子串的哈希值,並按照其起始位置%L的結果存在L個vector裏,對於每個vector只要單純看連續m個數是否有相同的數字即可,如果沒有就更新答案。
代碼:
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const ULL seed = 131;
const int MAXN = 1e5 + 10;
int m, l;
char s[MAXN];
ULL sum[MAXN], f[MAXN];
vector <ULL> vec[MAXN];
void init() {
f[0] = 1;
for (int i = 1; i <= 100000; i++)
f[i] = f[i - 1] * seed;
}
int cal() {
int ans = 0;
for (int i = 0; i < l; i++) {
int cnt = 0;
if ((int)vec[i].size() < m) continue;
map <ULL, int> mp;
for (int j = 0; j < m; j++) {
if (mp[vec[i][j]] == 1) ++cnt;
++mp[vec[i][j]];
}
if (cnt == 0) ++ans;
for (int j = 1; j + m <= (int)vec[i].size(); j++) {
--mp[vec[i][j - 1]];
if (mp[vec[i][j - 1]] == 1) --cnt;
if (mp[vec[i][j + m - 1]] == 1) ++cnt;
++mp[vec[i][j + m - 1]];
if (cnt == 0) ++ans;
}
}
return ans;
}
int main() {
//freopen("in.txt", "r", stdin);
init();
while (scanf("%d%d", &m, &l) == 2) {
scanf("%s", s + 1);
int len = strlen(s + 1);
for (int i = 1; i <= len; i++) {
sum[i] = sum[i - 1] * seed + s[i] - 'a';
}
for (int i = 0; i < l; i++) vec[i].clear();
for (int i = 1; i + l - 1 <= len; i++) {
int j = i + l - 1;
ULL tmp = sum[j] - sum[i - 1] * f[j - i + 1];
vec[(i - 1) % l].push_back(tmp);
}
printf("%d\n", cal());
}
return 0;
}