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

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值