Lemon觉得他需要一个复杂的密码来保证他的帐号的安全。他经过多日思考,决定使用一个长度为奇数的回文串来作为他的密码。
但是这个回文串太长了,Lemon记不住,于是Lemon决定把它记在本子上。当然直接把密码明文记录实在太愚蠢了,于是Lemon决定在记录时加入一些无意义的字符以保证密码的安全。
具体来说,假设Lemon的密码串是S,Lemon选择了一个不超过len(S)/2的正整数x,然后把S的前x个字符组成的字符串设为Left,把S的后x个字符组成的字符串设为Right,把S其余的字符组成的字符串设为Mid.
Lemon实际记录在密码本上的内容是A+Left+B+Mid+C+Right. 其中A,B,C都是无意义的字符串(有可能是空串)。他觉得这样就很安全了。
某一天,Melon无意发现了Lemon的笔记本,并发现了这个字符串。Melon决定把Lemon的密码破解出来。但是显然有不计其数的可能密码。
Melon认为,Lemon的密码一定很长,于是他想知道,这个字符串里隐藏的最长可能的密码有多长呢?
输入数据第一行包含一个正整数N,表示字符串的长度。
数据数据第二行包含一个长度为N的字符串,仅由小写字母组成,表示需要破译的字符串。
输出数据仅包含一个整数,表示最长可能的密码的长度。
对于20%的数据,满足N<=20
对于40%的数据,满足N<=300
对于60%的数据,满足N<=2000
对于100%的数据,满足N<=100000
用manachar算法求出每个字符为中心往两边拓展为回文串的最长长度。
这时有两种思路。
1.先枚举回文串再求两边的长度。
因为回文串变长,两端也只是缩小同样的长度,答案一定不会变劣。
所以我们只需要在极长回文串外求一个最长公共前后缀(KMP求出)即可。
2.先枚举两边的长度再求回文串的长度。
发现随着两边长度的变长,匹配的左边的部分会一直单调往右移,于是可以使用哈希 O ( n ) O(n) O(n)维护,之后就是求出区间最长回文串,可以二分答案后缩小边界再在缩小后的区间中求manachar求出的最长长度的最大值是否大于二分的答案。
第一种思路的代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstdlib>
#include<ctime>
#include<vector>
#include<map>
#define maxn 100005
#define INF 0x3f3f3f3f
using namespace std;
inline long long getint()
{
long long num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
int n;
char s[maxn],s1[maxn];
int p[maxn];
int nxt[maxn],f[maxn];
inline void manachar()
{
int mx=0,id=0;
for(int i=1;i<=n;i++)
{
if(