首页 > 代码库 > bzoj 4310 跳蚤

bzoj 4310 跳蚤

后缀数组+二分

1.

从后往前贪心扫

当必须分的时候就分一段

注意比较两个串大小时的细节

2.

先二分这个串第一次出现时在后缀数组上的位置

再二分具体是哪个串

从前往后扫,使右端点不断往左缩,当 右<=左 时分一段

快的飞起

1.

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define N 200005#define ll long longusing namespace std;char s[N];int rk[N],sa[N],wb[N],sum[N];void sasa(int n,int m){	int *x=rk,*y=wb;	for(int i=0;i<m;i++)sum[i]=0;	for(int i=0;i<n;i++)sum[x[i]=s[i]]++;	for(int i=1;i<m;i++)sum[i]+=sum[i-1];	for(int i=n-1;i>=0;i--)sa[--sum[x[i]]]=i;	for(int j=1,p=1;p<n;m=p,j<<=1)	{		p=0;		for(int i=n-j;i<n;i++)y[p++]=i;		for(int i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;		for(int i=0;i<m;i++)sum[i]=0;		for(int i=0;i<n;i++)sum[x[i]]++;		for(int i=1;i<m;i++)sum[i]+=sum[i-1];		for(int i=n-1;i>0;i--)sa[--sum[x[y[i]]]]=y[i];		swap(x,y);x[sa[0]]=0;p=1;		for(int i=1;i<n;i++)			x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]?p-1:p++;	}	return ;}int h[N];void calh(int n){	for(int i=1;i<=n;i++)rk[sa[i]]=i;	int k=0;	for(int i=0;i<n;i++)	{		if(k)k--;		int j=sa[rk[i]-1];		while(s[j+k]==s[i+k])k++;		h[rk[i]]=k;	}	return ;}int mn[N][20],lg[N],n;void ST(){	lg[0]=-1;	for(int i=1;i<=100000;i++)lg[i]=lg[i>>1]+1;	for(int i=1;i<=n;i++)mn[i][0]=h[i];	for(int i=1;i<20;i++)	{		for(int j=1;j<=n;j++)		{			if(j+(1<<(i-1))<=n)			{				mn[j][i]=min(mn[j][i-1],mn[j+(1<<(i-1))][i-1]);			}			else mn[j][i]=mn[j][i-1];		}	}return ;}int qur(int l,int r){	int k=lg[r-l+1];	return min(mn[l][k],mn[r-(1<<k)+1][k]);}bool cmp(int x,int len1,int y,int len2){	if(x<y)	{		int p=qur(x+1,y);		if(p>=len2&&p<len1)return 0;		return 1;	}	else if(x>y)	{		int p=qur(y+1,x);		if(p>=len1)return 1;		return 0;	}	else	{		if(len1<=len2)return 1;		return 0;	}}int k;bool pan(ll x){	int now=1;ll tot=0;	int pos,len;	for(int i=1;i<=n;i++)	{		ll pre=tot;		tot+=n-sa[i]-h[i];		if(tot>=x)		{			pos=i;len=h[i]+x-pre;			break;		}	}	int ta=n-1;	for(int i=n-1;i>=0;i--)	{		if(!cmp(rk[i],1,pos,len))return 0;		if(!cmp(rk[i],ta-i+1,pos,len))		{			ta=i,now++;		}	}	return now<=k;}int main(){	scanf("%d",&k);	scanf("%s",s);	n=strlen(s);	sasa(n+1,256);	calh(n);	ST();	ll sm=1LL*n*(n+1)/2;	for(int i=1;i<=n;i++)sm-=h[i];	ll l=1,r=sm;	while(l<r)	{		ll mid=(l+r)>>1;		if(pan(mid))r=mid;		else l=mid+1;	}	ll tot=0;	int pos,len;	for(int i=1;i<=n;i++)	{		ll pre=tot;		tot+=n-sa[i]-h[i];		if(tot>=l)		{			pos=i;len=h[i]+l-pre;			break;		}	}	for(int i=0;i<len;i++)	{		putchar(s[sa[pos]+i]);	}puts("");	return 0;}

2.

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define N 200005using namespace std;char s[N];int c[N],sa[N],m,n,rk[N],t1[N],t2[N],v[N];void saa(char *s,int n,int m){    int *x=t1,*y=t2;    for(int i=0;i<m;i++)c[i]=0;    for(int i=0;i<n;i++)c[x[i]=s[i]]++;    for(int i=1;i<m;i++)c[i]+=c[i-1];    for(int i=0;i<n;i++)sa[--c[x[i]]]=i;    int p=1;    for(int j=1;p<n;j<<=1,m=p)    {        p=0;        for(int i=n-j;i<n;i++)y[p++]=i;        for(int i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;        for(int j=0;j<m;j++)c[j]=0;        for(int i=0;i<n;i++)c[x[i]]++;        for(int j=1;j<m;j++)c[j]+=c[j-1];        for(int i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];        swap(x,y);x[sa[0]]=0;p=1;        for(int i=1;i<n;i++)          x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]?p-1:p++;    }    return ;}int h[N];void calh(int n){    for(int i=1;i<=n;i++)rk[sa[i]]=i;    int k=0;    for(int i=0;i<n;i++)    {        if(k)k--;        int j=sa[rk[i]-1];        while(s[i+k]==s[j+k])k++;        h[rk[i]]=k;    }    return ;}int main(){    scanf("%d %s",&m,s);    n=strlen(s);s[n]=0;    saa(s,n+1,300);    calh(n);    int l=1,r=n;    while(l<r)    {        int mid=(l+r)>>1,num=0,mn=n,m1=n;        for(int i=mid+1;i<=n;i++){m1=min(m1,h[i]);v[sa[i]]=m1;if(!h[i])num=m+1;}        for(int i=0;i<=n-1;i++)        {            if(mn==i)num++,mn=n;            if(v[i])mn=min(mn,i+v[i]);        }        if(num+1<=m)r=mid;else l=mid+1;        for(int i=mid+1;i<=n;i++)v[sa[i]]=0;     }    int u=l;    l=h[u]+1,r=n-sa[u];         while(l<r)    {         int mid=(l+r)>>1,k=u,num=0,mn=n,m1=mid;         for(int i=u+1;i<=n;i++){m1=min(m1,h[i]);v[sa[i]]=m1;}         v[sa[u]]=mid;         for(int i=0;i<n;i++)         {            if(mn==i)num++,mn=n;            if(v[i])mn=min(mn,i+v[i]);         }         if(num+1<=m)r=mid;else l=mid+1;         for(int i=k;i<=u;i++)v[sa[i]]=0;    }    for(int i=1;i<=l;i++)printf("%c",s[sa[u]+i-1]);    puts("");    return 0;}

  

bzoj 4310 跳蚤