【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;
}
NOI 2017 Bless All