跳蚤
很久很久以前,森林里住着一群跳蚤。一天,跳蚤国王得到了一个神秘的字符串,它想进行研究。
首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从 S 的所有子串中选择字典序最大的那一个,并在选出来的 k 个子串中选择字典序最大的那一个。他称其为“魔力串”。现在他想找一个最优的分法让“魔力串”字典序最小。
第一行一个整数 $k le 15$
接下来一个长度不超过 $10^5$ 的字符串
Sol
建sam,求出总共有多少子串。
可以二分答案k,然后求出第k大的串。
贪心从后往前取,遇到不合法就开新的一段,最后判断段数是否<=k
这样一定是对的。遇到不合法的串再怎么加字符也不合法。
遇到这种答案有单调性的可以选择二分。
#include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #define maxn 2000005 #define ll unsigned long long #define mod 1000000007 using namespace std; int n,num,rt=1,la=1,cnt=1; int ord[maxn],sz[maxn],top; ll sum[maxn],hash[maxn],ha[maxn],p[maxn]; char ch[maxn],a[maxn]; struct node{ int nex[26],par,Max; }s[maxn*2]; void ins(int c){ int np=++cnt,p=la;la=np; s[np].Max=s[p].Max+1; for(;p&&!s[p].nex[c];p=s[p].par)s[p].nex[c]=np; if(!p)s[np].par=rt; else { int q=s[p].nex[c]; if(s[q].Max==s[p].Max+1)s[np].par=q; else { int nq=++cnt; s[nq].par=s[q].par;s[nq].Max=s[p].Max+1; for(int i=0;i<26;i++)s[nq].nex[i]=s[q].nex[i]; s[q].par=s[np].par=nq; for(;p&&s[p].nex[c]==q;p=s[p].par)s[p].nex[c]=nq; } } } void calc(){ int tax[maxn]; for(int i=1;i<=cnt;i++)tax[s[i].Max]++; for(int i=1;i<=cnt;i++)tax[i]+=tax[i-1]; for(int i=1;i<=cnt;i++)ord[tax[s[i].Max]--]=i; for(int i=2;i<=cnt;i++)sz[i]=1;sz[1]=0; for(int i=cnt;i>=1;i--){ int k=ord[i]; for(int j=0;j<26;j++)sum[k]+=sum[s[k].nex[j]]; sum[k]+=sz[k]; } } void get(ll x){ top=0; int k=rt; while(1){ if(x<=sz[k])break; for(int i=0;i<26;i++){ if(sum[s[k].nex[i]]+sz[k]>=x){ a[++top]=i+'a';x-=sz[k]; k=s[k].nex[i];break; } else x-=sum[s[k].nex[i]]; } } for(int i=1;i<=top;i++)ha[i]=ha[i-1]*mod+a[i]; } bool check(int li,int ri){ int len=ri-li+1; int l=0,r=min(len,top); while(l<r){ int mid=l+r+1>>1; if(hash[li+mid-1]-hash[li-1]*p[mid]==ha[mid])l=mid; else r=mid-1; } if(l==top&&l==len)return 1; if(l==top)return 0; if(l==len)return 1; return a[l+1]>ch[li+l]; //a>li~ri 1 else 0 } bool pd(){ int la=n,co=0; for(int i=n;i>=1;i--){ if(!check(i,la)){ if(la==i)return 0; la=i,co++;i++; } if(co>num)return 0; } if(co+1>num)return 0; return 1; } int main(){ scanf("%d",&num); scanf("%s",ch+1);n=strlen(ch+1);p[0]=1; for(int i=1;i<=n;i++){ ins(ch[i]-'a'); hash[i]=hash[i-1]*mod+ch[i]; p[i]=p[i-1]*mod; } calc(); ll l=1,r=sum[1]; while(l<r){ ll mid=l+r>>1; get(mid); if(pd())r=mid; else l=mid+1; } get(l); for(int i=1;i<=top;i++)printf("%c",a[i]); return 0; }