【牛客小白77】D 字符串哈希

发布时间 2023-09-02 12:08:57作者: 从零开始的acm

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;
}