zoukankan      html  css  js  c++  java
  • 【CSP膜你赛】柠檬的密码(manacher 二分 单调性 st表)

    题目描述

      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的字符串,仅由小写字母组成,表示需要破译的字符串。

    输出格式

      输出数据仅包含一个整数,表示最长可能的密码的长度。
    输入样例
      25
      orzabcdxyzefgfeqwertydcba
    输出样例
      13
    提示
      最长的可能的密码是abcdefgfedcba,长度为13
      Lemon选择的x=4
      Left="abcd" Right="dcba" Mid="efgfe"
      A="orz" B="xyz" C="qwerty"
      时间限制1s
      对于20%的数据,满足N<=20
      对于40%的数据,满足N<=300
      对于60%的数据,满足N<=2000
      对于100%的数据,满足N<=100000

    分析

      在网上找了半天题解啥都没找到最后放弃了,去问的Master_Yi

      由于Right的右端点一定是原序列中的右端点,所以我们可以去枚举Right的左端点,也可以说是Right的长度,然后用hash值去找与它对称的Left

      用贪心的思想去找最左边的且与Right对称的 Left(这样可以给中间的mid留下足够的长度),从小到大枚举Left的左端点的坐标,可以发现它有单调性的

      模糊感性证明

      如果当前枚举的左端点形成的Left与Right不对称,之后的枚举新的Right的长度时,以这个点为左端点的Left肯定与Right不对称

      所以最左边与Right对称的Left的左端点一定随着Right的长度单增(或者说不下降

      于是就可以O(n)确定Left和Right,剩下中间的Mid,因为Mid一定是个回文串,可以用manacher预处理每个点的len数组,即以这个点为对称中心的最长子串长度

      设中间剩下的区间为(l,r),二分一下Mid的半径,设为k,用st表检验(l+k,r-k)中是否有len数组的值大于等于k的,如果有就更新答案,然后继续搜索。

      整了这么多东西,发现复杂度只有nlogn。。。。。。

      Code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,ans,ha[100005],st[100005][20],bw[100005],lg[100005];char ch[100005];
    int que(int l,int r){return l<=r?max(st[l][lg[r-l+1]],st[r-(1<<lg[r-l+1])+1][lg[r-l+1]]):0;}
    int main()
    {
        scanf("%d%s",&n,ch+1);bw[0]=1;
        for(int i=2;i<=n+1;i++)lg[i]=lg[i/2]+1;
        for(int i=1,r=0,mid=0;i<=n;bw[i]=bw[i-1]*29,i++)
        {
            st[i][0]=r>i?min(st[mid*2-i][0],r-i):1;
            while(ch[i-st[i][0]]==ch[i+st[i][0]])st[i][0]++;
            if(r<i+st[i][0])r=i+st[i][0],mid=i;ha[i]=(ch[i]-'a'+1)+ha[i-1]*29;
        }
        for(int k=1;k<=19;k++)for(int i=1;i<=n;i++)st[i][k]=max(st[i][k-1],i+(1<<(k-1))<=n?st[i+(1<<(k-1))][k-1]:0);
        for(int i=n,j=1,tmp=0;i>=1;i--)
        {
            tmp=ch[i]-'a'+1+tmp*29;
            while((j<n-i+1||ha[j]-ha[j-(n-i+1)]*bw[n-i+1]!=tmp)&&j<=n)j++;
            int l=0,r=(i-j)/2,mid,ret;
            while(l<=r&&j<=i)
            {
                mid=(l+r)>>1;
                if(que(j+mid,i-mid)>=mid)ret=mid,l=mid+1;
                else r=mid-1;
            }
            if(j<=i)ans=max((n-i+1)*2+ret*2-1,ans);
        }
        printf("%d
    ",ans);
    }

     

  • 相关阅读:
    poj3195 Generalized Matrioshkas(瞎搞题翻译)
    hdu2544最短路
    hdu2544最短路
    poj3195 Generalized Matrioshkas(栈)
    poj3195 Generalized Matrioshkas(栈)
    bzoj3171 [Tjoi2013]循环格
    bzoj3171 [Tjoi2013]循环格
    bzoj2245 [SDOI2011]工作安排
    bzoj2245 [SDOI2011]工作安排
    bzoj2668 [cqoi2012]交换棋子
  • 原文地址:https://www.cnblogs.com/firecrazy/p/11797639.html
Copyright © 2011-2022 走看看