• bzoj4310: 跳蚤


    一入字符深似海,从此AC是路人。

                  ——题记

    为什么恶心呢。

    在神犇的blog,我们才能知道,本质不同的子串=∑(Len−sa[i]−height[i])

    一脸蒙蔽的NN真是可爱啊。然而,这个sa是0~n-1的。

    神犇说:我们可以二分排名为mid的串,找到排名为mid的串的魔法就是这个(hhhhhh

    void get_chuan(LL mid)
    {
        for(int i=1;i<=n;i++)
        {
            LL p=(LL(n-(sa1[i]-1)-height[i]));
            if(mid>p)mid-=p;
            else
            {
                nowl=sa1[i];
                nowr=sa1[i]+height[i]+mid-1;
                return ;
            }
        }
    }

    我们可以据此从前往后贪心,假如遇到比自己字典序大的就新开一个block
    这时候玩着飞舞的白板笔的我,想到了求LCP常规操作——st表!!!

    OK调了一小时st表,又调了一小时LCP(呵呵真是个悲伤的故事)

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long LL;
    
    int n,a[110000];
    int sa1[110000],sa2[110000],Rank[110000];
    int tt[110000],Rsort[110000];
    void get_sa(int m)
    {
        for(int i=1;i<=n;i++)Rank[i]=a[i];
        
        memset(Rsort,0,sizeof(Rsort));
        for(int i=1;i<=n;i++)Rsort[Rank[i]]++;
        for(int i=1;i<=m;i++)Rsort[i]+=Rsort[i-1];
        for(int i=n;i>=1;i--)sa1[Rsort[Rank[i]]--]=i;
        
        int ln=1,p=0;
        while(p<n)
        {
            int k=0;for(int i=n-ln+1;i<=n;i++)sa2[++k]=i;
            for(int i=1;i<=n;i++)
                if(sa1[i]-ln>0)sa2[++k]=sa1[i]-ln;
                
            memset(Rsort,0,sizeof(Rsort));
            for(int i=1;i<=n;i++)Rsort[Rank[sa2[i]]]++;
            for(int i=1;i<=m;i++)Rsort[i]+=Rsort[i-1];
            for(int i=n;i>=1;i--)sa1[Rsort[Rank[sa2[i]]]--]=sa2[i];
            
            for(int i=1;i<=n;i++)tt[i]=Rank[i];
            
            Rank[sa1[1]]=1;p=1;
            for(int i=2;i<=n;i++)
            {
                if(tt[sa1[i-1]]!=tt[sa1[i]]||tt[sa1[i-1]+ln]!=tt[sa1[i]+ln])p++;
                Rank[sa1[i]]=p;
            }        
            ln*=2;m=p;
        }
    }
    int height[110000];
    void get_he()
    {
        int h=0;
        for(int i=1;i<=n;i++)
        {
            int j=sa1[Rank[i]-1];
            if(h!=0)h--;
            while(a[i+h]==a[j+h])h++;
            height[Rank[i]]=h;
        }
    }
    
    //-----------------sa------------------------------------------
    
    int Bin[30],Log[110000];
    int f[30][110000];
    int LCP(int x,int y)
    {
        if(x==y)return n-x+1;
        
        x=Rank[x],y=Rank[y];
        if(x>y)swap(x,y);
        x++;
        
        int k=Log[y-x+1];
        return min(f[k][x],f[k][y-Bin[k]+1]);
    }
    void get_st()
    {
        Bin[0]=1;for(int i=1;i<=25;i++)Bin[i]=Bin[i-1]*2;
        Log[1]=0;for(int i=2;i<=n ;i++)Log[i]=Log[i/2]+1;
         
        for(int i=2;i<=n;i++)f[0][i]=height[i];
        for(int j=1;j<=25;j++)
            for(int i=1;i+Bin[j]-1<=n;i++)
                f[j][i]=min(f[j-1][i],f[j-1][i+Bin[j-1]]);
    }
    
    //--------------use st to get LCP----------------
    
    int nowl,nowr;
    void get_chuan(LL mid)
    {
        for(int i=1;i<=n;i++)
        {
            LL p=(LL(n-(sa1[i]-1)-height[i]));
            if(mid>p)mid-=p;
            else
            {
                nowl=sa1[i];
                nowr=sa1[i]+height[i]+mid-1;
                return ;
            }
        }
    }
    bool compare(int l1,int r1,int l2,int r2)
    {
        int L1=r1-l1+1,L2=r2-l2+1,lcp=LCP(l1,l2);
        if(L1<=L2&&lcp>=L1)return true;
        if(L1>L2&&lcp>=L2)return false; 
        if(lcp>=L1&&lcp>=L2)return L1<L2; 
        return a[l1+lcp]<a[l2+lcp];
    }
    int K;
    bool check(LL mid)
    {
        get_chuan(mid);
        int cnt=1,last=n;
        for(int i=n;i>=1;i--)
        {
            if(compare(i,last,nowl,nowr)==false)
            {
                cnt++;last=i;
                if(cnt>K)return false;
            }
        }
        return true;
    }
    
    //---------------check---------------------
    
    char ss[110000];
    int main()
    {
        scanf("%d",&K);
        scanf("%s",ss+1);n=strlen(ss+1);
        for(int i=1;i<=n;i++)a[i]=ss[i]-'a'+1;
        
        get_sa(100);get_he();
        
        get_st();
        
        LL l=1,r=0,ans;
        for(int i=1;i<=n;i++)r+=(LL(n-(sa1[i]-1)-height[i]));
        while(l<=r)
        {
            LL mid=(l+r)/2;
            if(check(mid)==true)
            {
                r=mid-1;
                ans=mid;
            }
            else l=mid+1;
        }
        
        get_chuan(ans);
        for(int i=nowl;i<=nowr;i++)printf("%c",ss[i]);
        printf("
    ");
        return 0;
    }
  • 相关阅读:
    第二阶段冲刺第三天
    第二阶段冲刺第二天
    第二阶段冲刺第一天
    软件工程概论第十四周学习进度
    软件工程概论第十三周学习进度
    软件工程概论第十二周学习进度
    搜狗输入法
    冲刺第十天
    第二阶段冲刺第七天
    第二阶段冲刺第六天
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/8692284.html
Copyright © 2020-2023  润新知