bzoj4310: 跳蚤

Posted AKCqhzdy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4310: 跳蚤相关的知识,希望对你有一定的参考价值。

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

              ——题记

为什么恶心呢。

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

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

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

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 ;
        }
    }
}

 

这时候玩着飞舞的白板笔的我,想到了求LCP常规操作——st表!!!

#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("\n");
    return 0;
}

 

以上是关于bzoj4310: 跳蚤的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 4310 跳蚤

bzoj4310: 跳蚤

bzoj 4310 跳蚤

bzoj4310跳蚤 后缀数组+二分

后缀数组 hash求LCP BZOJ 4310: 跳蚤

目前的字符串