// Problem : String Cutting (NAIPC 2019) // Author : Darcy Best // Expected Result : WA // Complexity : O( |s| * ( log(|s|) + log(k) ) ) // Correct solution except does not handle the beginning of the string properly // if the string starts with the largest character #include #include #include #include #include #include using namespace std; typedef vector vi; void radixPass(vi &a, vi &b, vi &r, int n, int K, int off=0) { vi c(K+1, 0); for (int i = 0; i < n; i++) c[r[a[i]+off]]++; for (int i = 0, sum = 0; i <= K; i++) { int t = c[i]; c[i] = sum; sum += t; } for (int i = 0; i < n; i++) b[c[r[a[i]+off]]++] = a[i]; } // O(n log n) version vector suffix_array(string str) { int n = str.length(); if (n <= 1) return vector(n,0); vi RA(2*n, 0), SA(2*n), tmp(2*n); for (int i = 0; i < n; i++) RA[i] = (int)str[i] - CHAR_MIN + 1; for (int i = 0; i < n; i++) SA[i] = i; for (int k = 1; k < n; k <<= 1){ radixPass(SA,tmp,RA,n,max(n,256),k); radixPass(tmp,SA,RA,n,max(n,256),0); tmp[SA[0]] = 1; for(int i=1;i(SA.begin(), SA.begin()+n); } // Returns the number of c's that we can get at the beginning // and updates s and k accordingly int deal_with_char(string& s, char c, int& k){ int num_c = count(begin(s), end(s), c); if(s.empty() || k == 0 || num_c == 0) return 0; int groups_of_c = 0; for(int i=0;i<(int)s.length();i++) if(s[i] == c && (i == 0 || s[i-1] != c)) groups_of_c++; int cuts = groups_of_c - (s[0] == c); if(cuts <= k){ s = s.substr(s.find_last_of(c)+1); k -= cuts; return num_c; } int starting_chars = s.find_first_not_of(c); // Add dummy at the end to make life easier s = s.substr(starting_chars) + string(1,'a'-2); int n = s.length(); vector c_before(n, 0); priority_queue, greater > pq; int c_in_pq = 0; for(int i=0,j;i k){ c_in_pq -= pq.top(); pq.pop(); } } else { if(i == 0 || s[i-1] == c) c_before[i] = c_in_pq; } } vector sa = suffix_array(s); int best_idx = -1, most_c = 0; for(int i=0;i= most_c){ most_c = c_before[idx]; best_idx = idx; } } // Remove last dummy... s.pop_back(); // Remove bad prefix... s = s.substr(best_idx); // No more cuts allowed... k = 0; return most_c + starting_chars; } int main(){ int t; cin >> t; while (t--) { int k; string s; cin >> k >> s; for(char c='z';c>='a';c--) cout << string(deal_with_char(s,c,k),c); cout << s << endl; } }