【BZOJ 2803】【POI 2012】Prefixuffix

http://www.lydsy.com/JudgeOnline/problem.php?id=2803
核心思想是利用单调性。
因为长度为L的前缀和后缀循环同构是AB和BA的形式,我们设\(f(i)\)表示A的长度为i时B的最大长度。
有一个比较易证的结论\(f(i-1)\leq f(i)+2\)
但是并不好往这个结论上想。
单哈希被卡了qwq,改成双哈希了。
时间复杂度\(O(n)\)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int q = 29;
const int q2 = 79;
const int p = 233333333;
const int p2 = 100000007;
const int N = 1000003;

char s[N];
int f[N], powq[N], n, hash[N], r[N], powq2[N], hash2[N];

int get_ha(int l, int r) {
	return (hash[r] - 1ll * hash[l - 1] * powq[r - l + 1] % p + p) % p;
}

int get_ha2(int l, int r) {
	return (hash2[r] - 1ll * hash2[l - 1] * powq2[r - l + 1] % p2 + p2) % p2;
}

bool check(int l1, int r1, int l2, int r2) {
	return get_ha(l1, r1) == get_ha(l2, r2) && get_ha2(l1, r1) == get_ha2(l2, r2);
}

int main() {
	scanf("%d", &n);
	scanf("%s", s + 1);
	for (int i = 1; i <= n; ++i) r[i] = s[i] - 'a' + 1;
	
	powq[0] = powq2[0] = 1;
	for (int i = 1; i <= n; ++i) {
		powq[i] = 1ll * powq[i - 1] * q % p;
		powq2[i] = 1ll * powq2[i - 1] * q2 % p2;
	}
	hash[0] = hash2[0] = 0;
	for (int i = 1; i <= n; ++i) {
		hash[i] = (1ll * hash[i - 1] * q % p + r[i]) % p;
		hash2[i] = (1ll * hash2[i - 1] * q2 % p2 + r[i]) % p2;
	}
	
	int tmpl, tmpr, len = 0;
	for (int i = (n >> 1) - 1; i >= 0; --i) {
		len += 2; while (i + len > (n >> 1)) --len;
		tmpl = i + len; tmpr = n - i - len + 1;
		while (len && !check(i + 1, tmpl, tmpr, n - i))
			--len, --tmpl, ++tmpr;
		f[i] = len;
	}
	
	int ans = 0;
	tmpl = 0; tmpr = n + 1;
	for (int i = 1; i <= (n >> 1); ++i) {
		++tmpl; --tmpr;
		if (check(1, tmpl, tmpr, n))
			ans = max(ans, i + f[i]);
	}
	printf("%d\n", ans);
	return 0;
}
posted @ 2017-01-18 14:48  abclzr  阅读(293)  评论(0编辑  收藏  举报