贪心+树状数组维护一下 Intel Code Challenge Final Round (Div. 1 + Div. 2, Combined) D

http://codeforces.com/contest/724/problem/D

题目大意:给你一个串,从串中挑选字符,挑选是有条件的,按照这个条件所挑选出来的字符集合sort一定是最后选择当中最小的。

从pos=0开始挑选,每次挑选pos~pos+m-1这些位置中的字符,然后下一次再从之前挑选字符的位置开始的后面的m个中进行挑选。

思路:先贪心,按照字典序,每次找到该范围区间内最小的字符,因为该字符一定是串中的一部分,所以必然会被挑选的,于是我们先把这个pos的字符放入集合,并且对挑选过的位置做上标记。按照之前的方法可以先得到了一个集合,但是该集合不一定是最小的,例如m=2的时候cbbadca你前面挑选的集合为baca,但是你会发现还有一个b,如果放入的话字典序会更小,所以我们先得到目前集合中最大的字符,令他为ch,再for一遍把比ch小的再给放进来就好了。

说一下树状数组的作用,因为统计到末尾的时候,我不知道是直接结束还是再放入末尾区间内的某个字母,所以我利用树状数组统计了一下前面所有字符出现的次数,然后查询区间比末尾区间最小的字符串大的字符是否存在,如果存在就放入。

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define haha printf("haha
")
const int maxn = 100000 + 5;
int n, chlen;
char ch[maxn];
int tree[200 + 5];
vector<char> v;
char s[maxn];
bool vis[maxn];

void update(int x, int val = 1){
    for (int i = x; i <= 200; i += i & -i){
        tree[i] += val;
    }
}

int sum(int x){
    int ans = 0;
    for (int i = x; i > 0; i -= i & -i){
        ans += tree[i];
    }
    return ans;
}
///①并不是越长越好 ②最短长度是已经确定了的③所选出来的一定要比最短的那个的字典序要小
///目标,长度短,字典序短
void solve(){
    int pos = 0, slen = strlen(s);
    char minich = ch[pos];
    for (int i = pos + 1; i < n; i++){
        if(minich >=  ch[i]){minich = ch[i], pos = i;}
    }
    vis[pos] = true;
    v.pb(minich);
    while (pos < chlen){
        int minipos = pos + 1; minich = ch[minipos];
        for (int i = minipos + 1; i <= min(chlen, pos + n); i++){
            if (minich >= ch[i]){minich = ch[i], minipos = i;}
        }
        if (pos + n > chlen){
            int val = sum(200) - sum(minich);
            if (val == 0) break;
        }
        vis[minipos] = true;
        v.pb(minich);
        update(minich);
        pos = minipos;
    }
    sort(ALL(v));
    char maxch = v[v.size() - 1];
    for (int i = 0; i <= chlen; i++){
        if (!vis[i] && maxch > ch[i]){
            vis[i] = true; v.pb(ch[i]);
        }
    }
}

int main(){
    while (scanf("%d", &n) == 1){
        memset(vis, false, sizeof(vis));
        memset(tree, 0, sizeof(tree));
        memset(s, 0, sizeof(s));
        memset(ch, 0, sizeof(ch));
        scanf("%s", ch);
        chlen = strlen(ch);
        if (n > chlen) {printf("
"); continue;}
        chlen--;
        int cnt = 0;
        for (int i = 2; i <= chlen; i += 2){
            s[cnt++] = ch[i];
        }
        solve();
        sort(ALL(v));
        for (int i = 0; i < v.size(); i++){
            printf("%c", v[i]);
        }
        printf("
");
        v.clear();
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/heimao5027/p/5945680.html