求 hack 或证明结论
查看原帖
求 hack 或证明结论
1125442
luoyudong楼主2024/8/23 10:44

存在其中一个最长双倍回文子串是以某个位置为开始的最长回文子串。

瞎猜的结论,居然能过(

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>

const int maxn = 500000 + 10;
char a[maxn], s[2 * maxn];
int d[2 * maxn];

std::vector<int> v[maxn];
int r[maxn]; 

int main()
{
	int n;
	scanf("%d %s", &n, a + 1);
	for (int i = 1; i <= 2 * n + 1; i++) s[i] = i & 1 ? '#' : a[i / 2];
	for (int i = 1, l = 0, r = 0; i <= 2 * n + 1; i++)
	{
		d[i] = 0;
		if (i <= r) d[i] = std::min(d[2 * l - i], r - i + 1);
		while (d[i] <= std::min(i - 1, 2 * n + 1 - i) && s[i + d[i]] == s[i - d[i]]) d[i]++;
		if (i + d[i] - 1 > r) l = i, r = i + d[i] - 1;
	}
	for (int i = 1; i <= 2 * n + 1; i += 2)
	{
		if ((i - d[i]) / 2 + 1 > (i - 1) / 2) continue;
		v[(i - d[i]) / 2 + 1].push_back((i - 1) / 2);
		v[(i - 1) / 2 + 1].push_back(-(i - 1) / 2);
	}
	int ans = 0;
	std::multiset<int> set;
	for (int i = 1; i <= n; i++)
	{
		for (int j : v[i])
		{
			if (j >= 0) set.insert(j);
			else set.erase(set.find(-j));
		}
		if (set.empty()) continue;
		r[i] = 2 * *set.rbegin() - i + 1;
		if ((r[i] - i + 1) % 4 == 0)
		{
			int t = (r[i] - i + 1) / 4;
			if (d[(i + t - 1) * 2 + 1] - 1 >= 2 * t && d[(i + 3 * t - 1) * 2 + 1] - 1 >= 2 * t) ans = std::max(ans, r[i] - i + 1);
		}
	}
	printf("%d", ans);
	return 0;
}
2024/8/23 10:44
加载中...