Question:
It is required that a long string be decomposed into a maximum of K sub-strings, so that the Lexicographic Order of the N separate strings is the smallest.
Train of Thought Analysis:
It is not difficult to think of binary.
We can separate the rk major substring in the original string as the target string.
This is how we determine that this string meets the requirements, that is, how we divide other parts to make it the largest lexicographically ordered one.
We can easily find the string through rk, assuming it is in SA [T.
In the SA array, the lexicographic orders of substrings before t are smaller than those of the target string.
And there will be later than SA, we need to break down these strings.
We can scan from T to the height of n. If there is a height of 0, it will certainly not work, because the first of the strings is large. Then consider the case that it is not 0. That is to say, adding a letter next to the original string after the substring will be larger than the target string. Therefore, we need to cut it to make it smaller than the target string.
Finally, determine the number of strings you have split and whether it is smaller than K.
# Include <cstdio> # include <iostream> # include <cstring> # include <algorithm> # define maxn 100005 using namespace STD; typedef long ll; int SA [maxn], t1 [maxn], T2 [maxn], C [maxn]; void suffix (const char * STR, 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] = 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 (const char * STR, int N) {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 ;}} char STR [maxn]; ll sum [maxn]; int N, K; int CC [maxn]; bool OK (LL rk) {int T = lower_bound (sum + 1, sum + N, rk)-sum; int L = sa [T]; int r = sa [T] + Ke-sum [T-1] + height [T]-1; int Len = r-L + 1; // find the target string for (INT I = 0; I <n; I ++) CC [I] =-1; // If CC is not equal to-1, it means that a substring [I, I + Len] is cut down in I. if (SA [T] + Len <n-1) CC [SA [T] = Len; // if this string does not need to be cut, that is, his end is the end of the original string for (INT I = T + 1; I <n; I ++) {Len = min (Len, height [I]); If (LEN = 0) return false; if (SA [I] + Len <n-1) CC [SA [I] = Len;} int ans = 0; r = N; For (INT I = 0; I <n; I ++) {// there are some problems when cutting, that is, you can skip this section when you have already cut to yourself. If (I = r) {ans ++; r = N; If (ANS> = k) return false;} If (CC [I]! =-1) {r = min (R, I + CC [I]) ;}} return ans <K; // It is decomposed into ans + 1 segment} int main () {While (scanf ("% d", & K )! = EOF & K) {scanf ("% s", STR); n = strlen (STR) + 1; suffix (STR, N, 128); getheight (STR, n); sum [0] = 0; For (INT I = 1; I <n; I ++) sum [I] = sum [I-1] + (n-sa [I]-height [I]-1); ll l = 1, R = N * n, mid, ans = 1; while (L <= r) {mid = (L + r)> 1; if (OK (MID) {ans = mid; R = mid-1;} else l = Mid + 1;} int T = lower_bound (sum + 1, sum + N, ANS)-sum; int LL = sa [T]; int RR = sa [T] + ANS-sum [T-1] + height [T]-1; for (INT I = ll; I <= RR; I ++) printf ("% C", STR [I]); puts ("") ;}return 0 ;}
HDU 5030 Rabbit's string (suffix array)