您的位置:首页 > 编程语言 > C语言/C++

CSU-ACM2017暑假集训比赛2 E - ( ̄▽ ̄)/

2017-08-02 21:22 399 查看

E - ( ̄▽ ̄)/

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.


Input

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.


Output

Print the single line containing the lexicographically smallest string, that can be obtained using the procedure described above.


Example

Input

3
cbabc

Output

a

Input

2
abcab

Output

aab

Input

3
bcabcbaccba

Output

aaabb


Note

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".


题目描述很复杂,看了许久才看明白啥意思。

为方便表达,将两个字母中字典顺序靠前的称为“较小的字母”,反之称为“较大的字母”。

要求在原字符串中确定若干个位置,这些位置上的字符满足:从字符串中以每一个字符为起点,取出的若干个长度为 m 的子串中都包含它们,并且这些字符升序排列组成的字符串是所有可能结果中字典序最小的。

条件中“字典序最小”很重要。以输入样例3为例,有“aabb”和“aaabb”两种取法,前者长度较短,看上去更优,但后者字典序更小。所以必须仔细考虑算法方案。

经过思考可以知道,要使字典序最小,就需要在更大的字母存在时尽量多地加入更小的字母置于结果字符串的前部。而在更大字母数量一样时,较小字母全部加入结果前部自然能令结果字典序最小。所以总结出以下贪心方法:

扫描原字符串时,对每一个长度为 m 的小区间都找到小区间中最小的字母,以区间为单位记录遇到这个字母的次数,再将区间起点设置为这个最小字母的后一位;接着,在后面这个区间中找到最小的字母。若后面这个最小字母还大于前面的最小字母,则认为比后面这个最小字母还要小的字母被全部选中,对遇到字母次数的统计重置,将下一区间的起点设置为后发现的这个“较大的最小字母”的后一位。以此类推。

最终,只需要将比我们遇到的最大字母小的字母按升序输出,每个字母在原字符串中有几个就输出几个;然后输出遇到的最大字母,遇到几次输出几次,即得结果。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <map>
#include <cstring>
using namespace std;

char status[27], sample[100004];
map<char,int> stat; //用一个map存储每个字母出现的次数

int main(){
#ifdef TEST
freopen("test.txt", "r", stdin);
#endif // TEST

status[1] = 'a';
for(int i = 2; i <= 26; i++)//用来为map的重置提供坐标
status[i] = status[i-1]+1;

int m;
while(cin >> m){
for(int i = 1; i<= 26; i++)
stat[status[i]] = 0;
scanf("%s", sample);

int len = strlen(sample), sc = 1, last = 0;
for(int i = 0; i < len; i++){
stat[sample[i]]++;
}

for(int i = 0; i < len-m+1;){
int Pos = i;
char tempC = sample[i];
for(int j = i+1; j < i+m; j++){
if(sample[j] <= tempC){
Pos = j;
tempC = sample[j];
}
}
while(status[sc]<sample[Pos])sc++, last = 0;//sc用于保存当前所需的最大字母,last记录最大字母需要多少个。
if(sample[Pos]==status[sc])last++;
i = Pos+1;
}

for(int i = 1; i < sc; i++)//原字符串中有几个就输出几个
for(int j = 0; j < stat[status[i]]; j++)
putchar(status[i]);
for(int i = 0; i < last; i++)//遇到的最大字母,遇到几次就输出几个
putchar(status[sc]);
cout << endl;
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ 贪心 贪心算法