BZOJ 2803: [Poi2012]Prefixuffix

Description


对于两个串S1、S2,如果能够将S1的一个后缀移动到开头后变成S2,就称S1和S2循环相同。例如串ababba和串abbaab是循环相同的。
给出一个长度为n的串S,求满足下面条件的最大的L:
1. L<=n/2
2. S的L前缀和S的L后缀是循环相同的。

Input

第一行一个正整数n (n<=1,000,000)。第二行n个小写英文字母,表示串S。

Output

一个整数,表示最大的L。

Sample Input

15
ababbabababbaab

Sample Output

6

HINT

Source

结论题

循环同构可以分解为[1...i][i + 1...j]...[n - j + 1, n - i][n - i + 1...n]

然后s[1...i] = s[n - i + 1...n], s[i + 1...j] = s[n - j + 1, n - i]

中间那个是一个border,如果记f[i]表示s[i...n - i + 1]的border,那么f[i - 1] <= f[i] + 2

证明的话, 用f[i - 1]很容易构造出一个f[i - 1] - 2的f[i]

#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define fill(x, y) memset(x, y, sizeof x)
#define copy(x, y) memcpy(x, y, sizeof x)
using namespace std;

typedef unsigned long long LL;
typedef pair < int, int > pa;

inline int read()
{
	int sc = 0, f = 1; char ch = getchar();
	while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') sc = sc * 10 + ch - '0', ch = getchar();
	return sc * f;
}

const int MAXN = 1000005;
const int bas1 = 2333;
const int bas2 = 2551;
const int mod1 = 1e9 + 7;
const int mod2 = 1e9 + 9;

int n, ans;
char s[MAXN];

struct Hsh
{
	int f[MAXN], g[MAXN], p[MAXN], q[MAXN];

	inline void init()
	{
		p[0] = q[0] = 1;
		for (int i = 1; i <= n; i ++)
			p[i] = 1LL * p[i - 1] * bas1 % mod1, q[i] = 1LL * q[i - 1] * bas2 % mod2;
		for (int i = 1; i <= n; i ++)
			f[i] = (1LL * f[i - 1] * bas1 + s[i]) % mod1, g[i] = (1LL * g[i - 1] * bas2 + s[i]) % mod2;
	}

	inline pa get(int l, int r)
	{
		return mp((f[r] - 1LL * f[l - 1] * p[r - l + 1] % mod1 + mod1) % mod1, (g[r] - 1LL * g[l - 1] * q[r - l + 1] % mod2 + mod2) % mod2);
	}
}h;

int main()
{
#ifdef wxh010910
	freopen("data.in", "r", stdin);
#endif
	n = read();
	scanf("%s", s + 1);
	h.init();
	for (int i = n >> 1, j = 0; ~i; i --, j = min((n >> 1) - i, j + 2))
		if (h.get(1, i) == h.get(n - i + 1, n))
			for (; ~j; j --)
				if (h.get(i + 1, i + j) == h.get(n - i - j + 1, n - i))
				{
					ans = max(ans, i + j);
					break;
				}
	return printf("%d\n", ans), 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值