您的位置:首页 > 其它

HDU 4821 字符串哈希

2017-09-16 10:29 246 查看

题意:

给出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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hash