CF-Global Round 7-D1&D2

CF-Global Round 7-D1&D2

D2. Prefix-Suffix Palindrome (Hard version)

这道题是一个处理回文串的题目。然后加一个基础的双指针操作。

我是昨天才了解到这个算法的emmm.
hard version传送门

两个版本测试数据加强。
我直接写的hard版本。
easy版本可以用标准的hash来写。
这里介绍专门处理回文串的一个算法。
Manacher算法。详情移步链接

https://blog.csdn.net/qq_44624316/article/details/105018474

题目意思就是让你找到最长的回文串序列。
这个序列有要求。这个序列必须是由原序列的前缀和原序列的后缀组成的。
所以我们可以想到题目要求我们找到的序列是有这三部分组成的

原序列的前缀+回文串+原序列的后缀

原序列的前缀和原序列的后缀必须对称
这个部分好处理。就是双指针跑一遍就可以了。
中间的回文串我们就用Manacher算法。处理的复杂度O(N)级别。
上面链接很详细的介绍了。还有模板。
这里就不过多介绍了

我们在Manacher算法内部需要做一件事情。
这个回文串需要属于前缀的一部分或者后缀的一部分。
维护最大长度的回文串就行了。
跟左边邻近或者跟右边邻近需要分开讨论一下。并且标记。
下面代码中的flag就是标记

flag = 1时是跟左边邻近。
flag = 2时是个右边邻近。
代码部分更新最长回文串的时候直接把>=的全都更新了。找到的是最后一次符合要求的回文串。这个地方随便,>或者>=都行。>是找到第一次符合要求的回文串。
题目说了。凡是满足要求的随便输出一次就行。

当初因为考虑到t组数据,考虑要不要mst一下。
发现不用。。
Manacher()函数内部相当于有初始化了。不影响。

好啦~
代码部分:

#include <bits/stdc++.h>
#define mst(a, n) memset(a, n, sizeof(a))
using namespace std;
const int N = 1e6 + 10;

string s;
char ss[N << 1];
int p[N << 1];
int len;
int max_len;
int flag;

void Init(int left, int right)
{
	ss[0] = '$';
	ss[1] = '#';
	int j = 2;
	for (int i = left; i <= right; i++)
	{
		ss[j++] = s[i];
		ss[j++] = '#';
	}
	ss[j] = '\0';
	len = j;
}

void Manacher()
{
	int mx = 0;
	int id = 1;
	
	for (int i = 1; i < len; i++)
	{
		if (i < mx)
		{
			p[i] = min(p[2 * id - i], mx - i);
		}
		else
		{
			p[i] = 1;
		}
		while (ss[i - p[i]] == ss[i + p[i]])
		{
			p[i]++;
		}
		if (mx < i + p[i])
		{
			id = i;
			mx = i + p[i];
		}
		if (i == p[i])
		{
			if (p[i] - 1 >= max_len)
			{
				flag = 1;
				max_len = p[i] - 1;
			} 
		}
		if (i + p[i] == len)
		{
			if (p[i] - 1 >= max_len)
			{
				flag = 2;
				max_len = p[i] - 1;
			}
		}
	}
}

void solve()
{
	cin >> s;
	int lens = s.size();
	int left = 0, right = lens - 1;
	
	while (left < right && s[left] == s[right])
	{
		left++;
		right--;
	}
	if (left >= right)
	{
		cout << s << endl;
		return ;
	}
	Init(left, right);
	max_len = 0;
	Manacher();
	for (int i = 0; i < left; i++)
	{
		cout << s[i];
	}
	if (flag == 1)
	{
		for (int i = left, j = 0; j < max_len; j++, i++)
		{
			cout << s[i];
		}
	}
	else
	{
		for (int i = right - max_len + 1; i <= right; i++)
		{
			cout << s[i];
		}
	}
	for (int i = right + 1; i < lens; i++)
	{
		cout << s[i];
	}
	cout << endl;
}

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
} 
发布了112 篇原创文章 · 获赞 3 · 访问量 2624

猜你喜欢

转载自blog.csdn.net/qq_44624316/article/details/105025873
今日推荐