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;
}