You are given a string s, consisting of lowercase English letters, and the integer m.
One should choose some symbols from the given string so that any contiguous subsegment of length m has at least one selected symbol. Note that here we choose positions of symbols, not the symbols themselves.
Then one uses the chosen symbols to form a new string. All symbols from the chosen position should be used, but we are allowed to rearrange them in any order.
Formally, we choose a subsequence of indices 1 ≤ i1 < i2 < ... < it ≤ |s|. The selected sequence must meet the following condition: for every j such that 1 ≤ j ≤ |s| - m + 1, there must be at least one selected index that belongs to the segment [j, j + m - 1], i.e. there should exist a k from 1 to t, such that j ≤ ik ≤ j + m - 1.
Then we take any permutation p of the selected indices and form a new string sip1sip2... sipt.
Find the lexicographically smallest string, that can be obtained using this procedure.
The first line of the input contains a single integer m (1 ≤ m ≤ 100 000).
The second line contains the string s consisting of lowercase English letters. It is guaranteed that this string is non-empty and its length doesn't exceed 100 000. It is also guaranteed that the number m doesn't exceed the length of the string s.
Print the single line containing the lexicographically smallest string, that can be obtained using the procedure described above.
3 cbabc
a
2 abcab
aab
3 bcabcbaccba
aaabb
In the first sample, one can choose the subsequence {3} and form a string "a".
In the second sample, one can choose the subsequence {1, 2, 4} (symbols on this positions are 'a', 'b' and 'a') and rearrange the chosen symbols to form a string "aab".
Source
Intel Code Challenge Final Round (Div. 1 + Div. 2, Combined)
My Solution
ST表+贪心
ST表,用O(nlogn)的预处理,然后O(1)查询,找出ans中出现的最大的字母,
然后把比它小的字母都从小到大push到ans里,
然后贪心的去那个需要的最大字母的个数,
每次if(maxv == query_min(i, i + m - 1)) 则在这个 [ i, i + m -1 ]区间内找出最右端的一个maxv + 'a' 字母,//如果优先选左边的,则右边的还会取到,所以取区间最右边的maxv+'a'
就好。
复杂度 O(nlogn)
#include <iostream> #include <cstdio> #include <string> #include <cstring> using namespace std; typedef long long LL; const int maxn = 1e5 + 8; const int MAXN = 1e5 + 8; int stTable[MAXN][32], preLog2[MAXN], arr[MAXN]; inline void st_prepare(const int &n) { preLog2[1] = 0; for(int i = 2; i <= n; i++){ preLog2[i] = preLog2[i-1]; if((1 << (preLog2[i] + 1)) == i){ preLog2[i]++; } } for(int i = n - 1; i >= 0; i--){ stTable[i][0] = arr[i]; for(int j = 1; (i + (1 << j) - 1) < n; j++){ stTable[i][j] = min(stTable[i][j - 1], stTable[i + (1 << j - 1)][j - 1]); } } } inline int query_min(const int &l, const int r) { int len = r - l + 1, k = preLog2[len]; return min(stTable[l][k], stTable[r - (1 << k) + 1][k]); } int cnt[26]; string s, ans; //bool flag[maxn]; int main() { #ifdef LOCAL freopen("d.txt", "r", stdin); //freopen("d.out", "w", stdout); int T = 4; while(T--){ #endif // LOCAL ios::sync_with_stdio(false); cin.tie(0); for(int i = 0; i < maxn; i++){ arr[i] = 1e9 + 7; } int m, sz; cin >> m; cin >> s; sz = s.size(); ans.clear(); for(int i = 0; i < sz; i++){ cnt[s[i] - 'a']++; arr[i] = s[i] - 'a'; //cout << arr[i+1]; } st_prepare(sz); int maxv = -1; for(int i = 0; i < sz; i++){ if(i + m - 1 < sz){ maxv = max(maxv, query_min(i, i + m - 1)); } else break; } for(int i = 0; i < maxv; i++){ while(cnt[i]){ ans += 'a' + i; cnt[i]--; } } for(int i = 0; i < sz; i++){ //cout << i << endl; if(i + m - 1 < sz){ if(maxv == query_min(i, i + m - 1)){ for(int j = i + m - 1; j >= i; j--){ //在区域内找到最右边的maxv, 比赛的时候找的最左边的 maxv 尴尬 if(s[j] - 'a' == maxv){ ans += 'a' + maxv; i = j; //i += m - 1; //不能跳跃,看样例 //cout << i << endl; break; } } } } else break; } cout << ans << endl; #ifdef LOCAL memset(cnt, 0, sizeof cnt); cout << endl; } #endif // LOCAL return 0; }
Thank you!
------from ProLights