Cut a string into k blocks to minimize the largest block in the Lexicographic Order.
Orz wjmzbmr. It takes only one day to understand the problem.
You can use LCP (longest common prefix) to quickly compare the size of two substrings. It is enough to compare the size of the next character with the common prefix.
With this idea, we can first pre-process the LCP (suffix array + record O (2 nlog (2n) + O (N * n) of all substrings ), DP (O (4 * n )))
Then sort these substrings by lexicographically using LCP to start the second answer.
The second answer is the upper limit of the K block lexicographic orders. Assuming that I is used as the starting point, because the upper limit of the Lexicographic Order is known, we can immediately find the nearest vertex to be selected.
Now the problem is: knowing that each point can jump the r distance as far as possible, and finding whether there is a path, so that K hops return to the start point.
First, we assume that the R of each vertex is equal to 0, which means that each vertex can jump backward. In this way, we only need to use greedy ideas to enumerate any vertex as the starting point, the number of hops that can be jumped back. If the number of hops T <= K is returned, the value is true. Because each vertex can jump back, we can change several hops, so that t = K if the current number of points is less than K, that is, the number cannot be jumped to every step. Of course, it is false]
The problem is that if there are some points r = 0, that is, it cannot jump back, and other positions cannot jump to this position. Therefore, we thought that we would delete this vertex and subtract one from all affected vertices. We can skip three steps from, but now B (A <= B <= a + 3) is deleted, so a can only pick two steps, so after a can iterate n times at most, R of all vertices is not 0.
Code writing is frustrating...
#include <cstdio>#include <iostream>#include<algorithm>#include<cstring>#include<cmath>#include<queue>using namespace std;#define maxn 2005char str[maxn];int sa[maxn],t1[maxn],t2[maxn],c[maxn],n;void suffix(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]=str[i]]++; for(int i=1; i<m; i++)c[i]+=c[i-1]; for(int i=n-1; i>=0; i--)sa[--c[x[i]]]=i; for(int k=1; k<=n; k<<=1) { int p=0; for(int i=n-k; i<n; i++)y[p++]=i; for(int i=0; i<n; i++)if(sa[i]>=k)y[p++]=sa[i]-k; for(int i=0; i<m; i++)c[i]=0; for(int i=0; i<n; i++)c[x[y[i]]]++; for(int i=0; i<m; i++)c[i]+=c[i-1]; for(int i=n-1; i>=0; i--)sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1; x[sa[0]]=0; for(int i=1; i<n; i++) x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++; if(p>=n)break; m=p; }}int rank[maxn],height[maxn];void getheight(){ int k=0; for(int i=0; i<n; i++)rank[sa[i]]=i; for(int i=0; i<n; i++) { if(k)k--; if(!rank[i])continue; int j=sa[rank[i]-1]; while(str[i+k]==str[j+k])k++; height[rank[i]]=k; }}int f[maxn][30];void RMQINIT(){ for(int i=0;i<n;i++) f[i][0]=height[i]; for(int j=1;(1<<j)<=n;j++) for(int i=0;i+(1<<j)-1<n;i++) f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);}int RMQ(int l,int r){ if(l>r)swap(l,r); l++; int k=floor(log(r-l+1.0)/log(2.0)); return min(f[l][k],f[r+1-(1<<k)][k]);}int tn,k,st,mid;int lcp(int l,int r){ if(l==r) return n-l; return RMQ(rank[l],rank[r]);}int Lcp[1015][1015];struct node{ int l,r; int size; bool operator <(const node &x) const { int LCP=min(size,Lcp[l][x.l]); LCP=min(LCP,x.size); char a = LCP<size?str[l+LCP]:0; char b = LCP<x.size?str[x.l+LCP]:0; return a<b; }}a[1111111];vector<int> v[maxn];void debug(int pos){ for(int i=a[pos].l;i<a[pos].r;i++) { putchar(str[i]); } puts("");}bool vis[maxn];vector<int>far;bool cal(){ far.clear(); for(int i=0;i<tn;i++) { if(i==a[mid].l) { far.push_back(a[mid].size); continue; } int LCP=min(tn,Lcp[i][a[mid].l]); LCP=min(LCP,a[mid].size); if(LCP>=tn) { far.push_back(tn); continue; } else { if(str[i+LCP]<str[a[mid].l+LCP]) far.push_back(tn); else far.push_back(LCP); } } int ok=1; while(ok) { ok=0; for(int i=0;i<far.size();i++) { if(far[i]==0) { for(int j=0;j<far.size();j++) { if(j<i&&i<=j+far[j]) far[j]--; else if(j>i&&j+far[j]>=i+far.size()) far[j]--; } ok=1; far.erase(i+far.begin()); } } } if(far.size()<k) return false; int len=far.size(); for(int i=0;i<len;i++) far.push_back(far[i]); for(int i=0;i<len;i++) { int times=0; for(int j=i;j<i+len;j+=far[j]) times++; if(times<=k) return true; } return false;}int main(){ int cas; scanf("%d",&cas); while(cas--) { scanf("%d%d",&n,&k); scanf("%s",str); tn=n; if(k==1) {puts(str);continue;} for(int i=n;i<2*n;i++) str[i]=str[i-n]; n*=2; str[n]=0; n++; suffix(128); getheight(); RMQINIT(); n--; int top=0; for(int i=0;i<tn;i++) { for(int j=i;j<i+tn;j++) { a[++top].l=i; a[top].r=j+1; a[top].size=j+1-i; } } for(int i=0;i<=tn;i++) for(int j=0;j<=tn;j++) Lcp[i][j]=lcp(i,j); sort(a+1,a+top+1); int l=1,r=top,ans; while(l<=r) { mid=(l+r)/2; if(cal()) { ans=mid; r=mid-1; } else { l=mid+1; } } debug(ans); } return 0;}