BZOJ2081 [POI2010]Beads

题目蓝链

Solution

首先\(\mathcal{O}(n)\)预处理出任意一个前缀的HASH值,然后就可以\(\mathcal{O}(1)\)求出任意区间的HASH值

然后就直接枚举\(k\),统计一下出现了多少种不同的区间段就可以了,用\(map\)或HASH表均可以实现

时间复杂度\(\mathcal{O}(k \cdot ln(k))\)

Code

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>

using namespace std;

#define squ(x) ((LL)(x) * (x))
#define debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef pair<int, int> pii;

inline int read() {
	int sum = 0, fg = 1; char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') fg = -1;
	for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
	return fg * sum;
}

const int base = 19260817;
const int mod = 998244353;
const int maxn = 2e5 + 10;

__gnu_pbds::gp_hash_table<int, bool> mp;

int add(int x, int y) {
	x += y;
	if (x >= mod) x -= mod;
	if (x < 0) x += mod;
	return x;
}
int mul(int x, int y) { return (LL)x * y % mod; }

int n, a[maxn], b[maxn], Pow[maxn], q[maxn], top;

int main() {
#ifdef xunzhen
	freopen("hash.in", "r", stdin);
	freopen("hash.out", "w", stdout);
#endif

	n = read(); Pow[0] = 1;
	for (int i = 1; i <= n; i++) Pow[i] = mul(Pow[i - 1], base);
	for (int i = 1; i <= n; i++) a[i] = add(mul(a[i - 1], base), b[i] = read());
	for (int i = n; i >= 1; i--) b[i] = add(mul(b[i + 1], base), b[i]);

	int ans = 0;
	for (int k = 1; k <= n; k++) {
		int cnt = 0;
		mp.clear();
		for (int i = 1; i <= n; i += k) {
			int l = i, r = i + k - 1;
			if (r > n) continue;
			int hash1 = add(a[r], -mul(a[l - 1], Pow[k]));
			int hash2 = add(b[l], -mul(b[r + 1], Pow[k]));
			if (mp.find(hash1) == mp.end()) cnt++, mp[hash1] = 1, mp[hash2] = 1;
		}
		if (cnt == ans) q[++top] = k;
		if (cnt > ans) {
			ans = cnt;
			q[top = 1] = k;
		}
	}

	printf("%d %d\n", ans, top);
	for (int i = 1; i <= top; i++) printf("%d%c", q[i], i < top ? ' ' : '\n');

	return 0;
}

Summary

这应该算是我做的第一道比较正式的HASH题了,第一次用了求区间HASH值的这个技巧

done(2018.8.31)
upt(2018.9.26): 之前写的题,一直没发

posted @ 2018-09-26 22:26  xunzhen  阅读(153)  评论(0编辑  收藏  举报