【牛客小白77】D 字符串哈希
https://ac.nowcoder.com/acm/contest/64384/D
题意
给你一串长度为 \(n (n \leq 10^6)\) 的密码,它是顺序输入的,如果截止到某一位,输入的最后 \(m\) 个字符是密码,那么之前输入的所有东西都清除。问目前检测到 \(k (m*k \leq n)\) 次输入成功,问密码可能的种类数
思路
很容易想到枚举密码,这样差不多是 \(n\) 种,然后我们需要对密码进行check。
如果暴力枚举check,总复杂度 \(O(n^2)\) ,超时
别的办法?字符串哈希!对当前字符串映射到的数值+1,然后记录该字符串最后一位出现的位置。如果上一次出现的最后一位比当前第一位还大或者一样,那么不合法,continue掉
code
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
const int N = 1e6 + 50, seed = 31;
int n, m, k;
char s[N];
ull h[N], base[N];
map<ull, int> cnt, las;
ull Hash(int l, int r) {
return h[r] - h[l - 1] * base[r - l + 1];
}
int main () {
ios::sync_with_stdio(false);
cin >> n >> m >> k >> s + 1;
h[0] = 0, base[0] = 1;
for(int i = 1; i <= n; i++) {
base[i] = base[i - 1] * seed;
h[i] = h[i - 1] * seed + s[i] - '0';
}
for(int i = 1; i <= n; i++) {
if(i + m - 1 > n) break;
ull tem = Hash(i, i + m - 1);
if(las[tem] >= i) continue;
las[tem] = i + m - 1;
cnt[tem]++;
}
int ans = 0;
for(auto i : cnt) {
if(i.second == k) ans++;
}
cout << ans << endl;
return 0;
}