Uva 11491 Erasing and Winning

Thinking about it:

  题目要求是删除D个数,因为总共有N个数,因此也可以看作在N个数中选择d = N - D个数。

  怎么选呢?选择第一个数时,肯定是在[ 0, N - D ] 的位置上选,既然选,肯定在这区间内选最大的。如果最大值有多个,那么选位置靠前的,因为这样可以选第一个数的最大值可能用于第二个数。假设,第一个数选的位置为p, 那么第二个数则在[ p+1, N - D + 1 ]的位置选,以此类推,直至全部选完。

  因为是在一个区间内选取最大值,所以在选最大值上可以做一些预处理:计算每个位置 i, 离 i 两边最近,且比 i 所在位置值要大的位置。比如 13215,i = 2 时,比 2 大的值,左边最近的在1, 右边最近的在4。知道这两个值,就可以快速判断 2 在区间 [ 1 ,3 ] ,[ 2, 3 ]上是不是最大的了。

 

Refefence:

  1. 《算法竞赛入门经典(第2版)》

  2. http://blog.csdn.net/u014800748/article/details/43671343

 

PS:

  这题的解决方法有很多,我在AC后看了他人的题解,每个人的实现方法都有所差异,有些方法值得学习。

 

Code:

/**
 * AC @ Sep 8th 2015
 * Run Time : 0.049s
 */
#include <bits/stdc++.h>

using namespace std;

const int MAXN = 10e5 + 50;
int N, D;
int l[MAXN], r[MAXN];
// l[i]; the nearest pos bigger than digits[i] on the left
// r[i]; the nearest pos bigger than digits[i] on the right
string digits;
std::vector<int> ans;

void init() {
    int hash[15]; // right
    for (int i = 0; i < 15; ++i) {
        hash[i] = MAXN;
    }
    for (int i = N-1; i >= 0; --i) {
        int tmp = MAXN;
        for (int j = digits[i]- '0' + 1; j < 10; ++j) {
            tmp = min(hash[j], tmp);
        }
        hash[digits[i]- '0'] = i;
        r[i] = tmp;
    }
    memset(hash, -1, sizeof(hash)); // left
    for (int i = 0; i < N; ++i) {
        int tmp = -1;
        for (int j = digits[i]-'0' + 1; j < 10; ++j) {
            tmp = max(hash[j], tmp);
        }
        hash[digits[i]- '0'] = i;
        l[i] = tmp;
    }
}

void find(int start, int d) {
    if (!d) {
        return ;
    }
    int i;
    for(i = start; i <= N - d; ++ i) {
        if (l[i] < start && r[i] > N-d) {
            break;
        }
    }
    ans.push_back(digits[i]-'0');
    find(i+1, d-1);
}

void work() {
    init();
    ans.clear();
    find(0, N-D);
    for (std::vector<int>::iterator it = ans.begin(); it != ans.end(); ++it) {
        cout << *it;
    }
    cout << endl;
}

int main(int argc, char const *argv[]) {
    ios::sync_with_stdio(false);
    cin.tie(0);
    while(cin >> N >> D && (N + D)) {
        cin >> digits;
        work();
    }
    return 0;
}

  

posted @ 2015-09-08 12:13 Emerald 阅读(...) 评论(...) 编辑 收藏