JZOJ 4366. 【GDKOI2016】项链

15 篇文章 0 订阅
4 篇文章 0 订阅

Description

Description

Input

输入一行,小写字母组成的字符串,代表项链上珍珠的颜色,可能从项链的任意位置开始。

Output

输出一行,拼接后对称的新项链最长长度。

Sample Input

Sample Input

Sample Output

Sample Output

Data Constraint

Data Constraint

Solution

  • 先贴一个 Twilight 大神的 Solution :

Solution

  • 我用的扫描线+并查集,时间复杂度 O(Nα(N))

  • 由于本人较弱,再贴一个 Crazy 大爷的扫描线大法:

Solution

  • 黑白点染色。用并查集记录一团不可行的点的最左的点的位置。

  • 倒着做一遍,顺便染色和统计答案即可。

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;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值