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

浙公网安备 33010602011771号