一入字符深似海,从此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; }