zoukankan      html  css  js  c++  java
  • [后缀数组]JZOJ 3337 wyl889的TLE

    Description

    wyl8899今天也很刻苦的在做老师布置下来的题目!

    这一天老师布置的题目是这样的:

    给出两个仅含小写字母的字符串A和B,输出最大的k,使得A[1..k]是B的子串。

    A和B的长度都不会超过50000。

    很显然他并不知道正确的做法,但是他居然卡着时间过掉了老师给的数据!

    你找到了他提交给老师的程序,经过测试你惊讶的发现,他的程序运行时间恰好是最终答案,单位是毫秒。

    你现在找到了老师给的数据中的一笔,你决定至多修改A串中的一个字母,使得他的程序尽可能的慢。

    现在,你能告诉我修改数据之后他的程序在这个测试点的运行时间么?(单位当然还是毫秒)
     

    Input

    两行,每行一个仅含小写字母的字符串,分别是A和B。

    保证A和B的长度都不超过50000。

    Output

    你修改数据之后,wyl8899的程序在这个测试点的运行时间,单位是毫秒。
     

    Sample Input

    输入1:
    adbc
    aabbabd

    输入2:
    aab
    aabcc
     

    Sample Output

    输出1:
    3

    输出2:
    3
     

    Data Constraint

    保证A和B的长度都不超过50000。
     

    Hint

    数据是在Windows下生成的,测评环境是Linux。

    由于换行符的差异,对于C/C++选手,请不要使用gets(s)读入一行字符,建议使用scanf("%s",s)的形式。

    Pascal选手直接使用readln()读入一行即可,理论上readln()不会受到不同换行符的影响。

    分析

    发现可以枚举端点i,然后修改字符前的长度是len=LCP(B[i..m],A)

    则ans=max(len+1+LCP(B[i+len+1..m],A[len+2..n]))

    考场看到LCP时 心 肺 停 止

    背完SA板子以后随便搞搞就欧克了

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int N=1e6+10;
    int n,n1,n2,m;
    int c[N],x[N],y[N],sa[N],rk[N],height[(1<<21)+1][21],pow[21],ans;
    char s[N],s2[N];
    
    int MIN(int l,int r) {
        if (l>r) swap(l,r);
        l++;
        int ans=2147483647;
        for (int k=20;k>=0;k--)
            if (l+pow[k]-1<=r) {
                ans=min(ans,height[l][k]);
                l+=pow[k];
            }
        return ans;
    }
    
    void Solve() {
        int len,l;
        for (int i=1;i<=n2;i++) {
            len=min(min(n1,n2-i+1),MIN(rk[i],rk[n2+1]));
            ans=max(ans,min(min(n1,n2-i+1),len+1));
            ans=max(ans,min(min(n1,n2-i+1),len));
            l=min(min(n1,n2-i+1)-len-1,MIN(rk[i+len+1],rk[n2+len+2]));
            ans=max(ans,len+1+l);
        }
    }
    
    void SA() {
        memset(c,0,sizeof c);
        for (int i=1;i<=n;i++) c[x[i]=s2[i]]++;
        for (int i=1;i<=m;i++) c[i]+=c[i-1];
        for (int i=n;i;i--) sa[c[x[i]]--]=i;
        for (int k=1;k<=n;k<<=1) {
            memset(c,0,sizeof c);int cnt=0;
            for (int i=n-k+1;i<=n;i++) y[++cnt]=i;
            for (int i=1;i<=n;i++) if (sa[i]>k) y[++cnt]=sa[i]-k;
            for (int i=1;i<=n;i++) c[x[i]]++;
            for (int i=1;i<=m;i++) c[i]+=c[i-1];
            for (int i=n;i;i--) sa[c[x[y[i]]]--]=y[i],y[i]=0;
            swap(x,y);cnt=0;
            x[sa[1]]=++cnt;
            for (int i=2;i<=n;i++)
            x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?cnt:++cnt;
            if (cnt==n) break;
            m=cnt;
        }
    }
    
    void Get_Height() {
        for (int i=1;i<=n;i++) rk[sa[i]]=i;
        int k=0;
        for (int i=1;i<=n;i++) {
            if (rk[i]==1) continue;
            k=max(0,k-1);
            int j=sa[rk[i]-1];
            while (s2[j+k]==s2[i+k]&&i+k<=n&&j+k<=n) k++;
            height[rk[i]][0]=k;
        }
    }
    
    void RMQ() {
        for (int k=1;k<=20;k++)
            for (int i=1;i<=n;i++) height[i][k]=min(height[i][k-1],height[i+pow[k-1]][k-1]);
    }
    
    int main() {
        scanf("%s",s+1);scanf("%s",s2+1);
        n1=strlen(s+1);n=strlen(s2+1);m='z';n2=n;
        for (int i=n+1;i<=n1+n;i++) s2[i]=s[i-n];
        n+=n1;
        pow[0]=1;
        for (int i=1;i<=20;i++) pow[i]=pow[i-1]<<1;
        SA();memset(height,0x7f,sizeof height);
        Get_Height();
        RMQ();
        Solve();
        printf("%d",ans);
    }
    View Code
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    【BZOJ2384】[Ceoi2011]Match KMP
    【BZOJ2482】[Spoj1557] Can you answer these queries II 线段树
    【BZOJ2506】calc 分段+vector+莫队
    【BZOJ2600】[Ioi2011]ricehub 双指针法
    【BZOJ4898】[Apio2017]商旅 分数规划+SPFA
    【BZOJ4417】[Shoi2013]超级跳马 矩阵乘法
    【BZOJ2707】[SDOI2012]走迷宫 Tarjan+拓扑排序+高斯消元+期望
    【BZOJ2730】[HNOI2012]矿场搭建 Tarjan
    【BZOJ4987】Tree 树形DP
    【BZOJ3502/2288】PA2012 Tanie linie/【POJ Challenge】生日礼物 堆+链表(模拟费用流)
  • 原文地址:https://www.cnblogs.com/mastervan/p/11166674.html
Copyright © 2011-2022 走看看