bzoj 4310 跳蚤

后缀数组+二分

1.

从后往前贪心扫

当必须分的时候就分一段

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

2.

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

再二分具体是哪个串

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

快的飞起

1.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
#define ll long long
using 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 200005
using 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;
}

  

posted @ 2017-04-20 09:31  SD_le  阅读(254)  评论(0编辑  收藏  举报
重置按钮