Description
Input
输入一行,小写字母组成的字符串,代表项链上珍珠的颜色,可能从项链的任意位置开始。
Output
输出一行,拼接后对称的新项链最长长度。
Sample Input
Sample Output
Data Constraint
Solution
- 先贴一个 Twilight 大神的 Solution :
我用的扫描线+并查集,时间复杂度 O(N∗α(N)) 。
由于本人较弱,再贴一个 Crazy 大爷的扫描线大法:
黑白点染色。用并查集记录一团不可行的点的最左的点的位置。
倒着做一遍,顺便染色和统计答案即可。
Code
#include<cstdio>
using namespace std;
const int N=4e5+5;
int n,ans,id,tot1,tot2;
int first1[N],next1[N],en1[N];
int first2[N],next2[N],en2[N];
int p[N],f[N];
bool col[N];
char s[N];
inline int min(int x,int y)
{
return x<y?x:y;
}
inline int max(int x,int y)
{
return x>y?x:y;
}
inline void Manacher()
{
for(int i=n;i;i--) s[i<<1]=s[i],s[i<<1|1]='#';
n=n<<1|1,s[1]='#',s[0]='$';
for(int i=1;i<=n;i++)
{
p[i]=p[id]+id>i?min(p[id*2-i],p[id]+id-i):1;
while(s[i-p[i]]==s[i+p[i]]) p[i]++;
if(p[i]+i>p[id]+id) id=i;
}
for(int i=1;i<=n;i++) p[i]--;
}
inline void insert1(int x,int y)
{
next1[++tot1]=first1[x];
first1[x]=tot1;
en1[tot1]=y;
}
inline void insert2(int x,int y)
{
next2[++tot2]=first2[x];
first2[x]=tot2;
en2[tot2]=y;
}
int get(int x)
{
return f[x]==x?x:f[x]=get(f[x]);
}
int main()
{
char ch=getchar();
while(ch>='a' && ch<='z') s[++n]=ch,ch=getchar();
for(int i=n<<1;i>n;i--) s[i]=s[i-n];
n<<=1,Manacher();
for(int i=1;i<=n;i++)
{
f[i]=i;
insert1(i-p[i],i);
insert2(i+p[i],i);
}
for(int i=n;i;i--)
{
for(int j=first2[i];j;j=next2[j])
{
int x=min(n,en2[j]+(n>>2)),y=!col[x]?x:get(x)-1;
ans=max(ans,y-en2[j]);
}
for(int j=first1[i];j;j=next1[j])
{
int x=en1[j];
col[x]=true;
if(col[x-1]) f[get(x)]=x-1;
if(col[x+1]) f[get(x+1)]=x;
}
}
printf("%d",ans);
return 0;
}