bjfu1099 度度熊大战僵尸

这也是2011年百度之星的一道题。

这题我就是乱搞搞过的,打代码之前自己心里也没底,不知道能不能过的。

我的做法很简单,就是按时间顺序依次构造能杀死的僵尸血量,找到第k小的。构造的方法也很暴力:对t时刻,第i个武器新构造出来的血量,就是用ai+t*bi依次去加之前时刻构造出来的血量。所以解题的关键就在于不断地对这个方法进行剪枝与优化。

第一个优化是,t只用从1到k,而不用再往后,很好理解。

第二,考虑如何存储已经产生的血量。我是用了一个set保存所有的血量,然后每一次循环时把set中的内容导出到一个数组里。往set里插入数据和查找数据都是log n的,所以把数据导出到数组里复杂度为n*log(n)。这里又可以加入一个优化,每次导出到数组里的元素只用前K个。

第三个优化,如果当t时刻,所有的ai+bi*t都比当前的结果大,则可以结束。

这样打完之后,自己测了几组数据,很快出结果,但是交上去依然超时。于是自己构造了几组变态数据,一测,发现瓶颈依然在set那里,因为对于大型的测试数据,后来的时刻产生的大量血量值都是以前出现过的,如果用hash来判断血量值是否出现过,就能把这里的复杂度从log(n)降到O(1),因为这里是瓶颈,所以效果很明显。果然,加上以后就过了。

代码如下:

/*

 * bjfu1099

 * Author    : ben

 */

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <cmath>

#include <ctime>

#include <iostream>

#include <algorithm>

#include <queue>

#include <set>

#include <map>

#include <stack>

#include <string>

#include <vector>

#include <deque>

#include <list>

#include <functional>

#include <numeric>

#include <cctype>

using namespace std;

#ifdef ON_LOCAL_DEBUG

#else

#endif

typedef long long LL;

const int maxn = 11;

int N, K;

int a[maxn], b[maxn];

int buf[51000];

set<int> S;



const int maxh = 1000007;

bool hash[maxh];

int hval[maxh];



void hash_insert(int num) {

    int k = num % maxh;

    while (hash[k] && hval[k] != num) {

        k = (k + 1) % maxh;

    }

    if (!hash[k]) {

        hash[k] = true;

        hval[k] = num;

    }

}



bool hash_find(int num) {

    int k = num % maxh;

    while (hash[k] && hval[k] != num) {

        k = (k + 1) % maxh;

    }

    return hash[k];

}



int work() {

    bool hasnew = true;

    S.insert(0);

    hash_insert(0);

    int offset, I;

    for (int t = 1; t <= K; t++) {

        if (hasnew) {

            I = 0;

            set<int>::iterator it = S.begin();

            while (it != S.end() && I <= K) {

                buf[I++] = *(it++);

            }

            hasnew = false;

        }

        offset = (I > K) ? buf[K] : 0x7fffffff;

//        printf("t = %d, offset = %d, I = %d\n", t, offset, I);

        bool flag = false;

        for (int i = 0; i < N; i++) {

            a[i] += b[i];

            if (a[i] > offset) {

                continue;

            }

            for (int j = 0; j < I; j++) {

                int p = a[i] + buf[j];

                if (p < offset) {

                    flag = true;

                    if (!hash_find(p)) {//对于大型的测试数据,后面的插入太多重复,用hash能降掉这里的logn的复杂度

//                    if (S.count(p) <= 0) {

                        hasnew = true;

                        S.insert(p);

                        hash_insert(p);

                    }

                } else {

                    break;;

                }

            }

        }

        if (!flag) {

            break;

        }

    }

    return buf[K];

}



int main() {

#ifdef ON_LOCAL_DEBUG

    freopen("data.in", "r", stdin);

#endif

    memset(hash, false, sizeof(hash));

    scanf("%d%d", &N, &K);

    for (int i = 0; i < N; i++) {

        scanf("%d%d", &a[i], &b[i]);

    }

    printf("%d\n", work());

    return 0;

}

 

你可能感兴趣的:(B)