Intel Code Challenge Final Round D. Dense Subsequence 二分思想

D. Dense Subsequence
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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.

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

题意:给你一个长度至多1e5的字符串,和一个数字m(<=1e5),要求你找出一组下标,使得任意的长度为m的连续的字符串序列都包括你选的下标,输出字典序最小的一组解;

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <set>
using namespace std;
#define MM(a,b) memset(a,b,sizeof(a))
#define SC scanf
typedef long long ll;
typedef unsigned long long ULL;
const int mod = 1000000007;
const double eps = 1e-10;
const int inf = 0x3f3f3f3f;
const int N=1e5+10;
int max(int a,int b) {return a>b?a:b;};
int min(int a,int b) {return a<b?a:b;};

char s[N];
int num[30];
int main()
{
    int m;
    while(~SC("%d",&m)){
        MM(num,0);
        SC("%s",s+1);
        char c;
        for(c='a';c<='z';c++){
            int k=0,flag=1;
            for(int i=1;s[i]!='';i++){
                k++;
                if(s[i]<=c) {
                   k=0;
                   if(s[i]==c){
                    num[c-'a']++;
                   }
                }
                if(k>=m) flag=0;
            }
            if(flag) break;
        }
        num[c-'a']=0; int k=0,now;
        for(int i=1;s[i]!='';i++){
            k++;
            if(s[i]<c) k=0;
            else if(s[i]==c) now=i;
            if(k==m) {
                num[c-'a']++;
                i=now;
                k=0;
            }
        }
        for(char x='a';x<=c;x++)
         {
           while(num[x-'a']--) {
                printf("%c",x);
           }
         }
         printf("
");
    }
    return 0;
}

  分析:

1.首先可以发现从从a到z枚举出选出的字符的最大值的话,那么要保证字典序最小的话,比当前枚举的字符小的都要选取(二分思想)

2.那么我们只要从a到z枚举选取的字符的最大值qq,首先所有qq都选,判断能否满足题意;

3.接下来只要确定qq的个数就好了,从左到右枚举,一当出现k==m的情况,就选取最近的一个qq

原文地址:https://www.cnblogs.com/smilesundream/p/5978722.html