[多维DP] 洛谷P1541 乌龟棋(高端技巧的使用问题)

题目

LP1541

思路

可以看到,本题需要用一个40进制的4位数来表示状态。自然想到了基金管理,自然就想到了两种方法:四十进制数和状态池。
显然本题用40进制数,数组会太大(40^4=2560000),所有考虑用状态池。写的也很顺利,然后TLE了一半的点。
而正解就是个简单的多维状态,用多维数组来表示。


启示:可以说,在noip阶段,紫书上的题很难很难。绝大多数的题用到的技巧,都不会在noip这种级别的比赛中出现,而且很多的题的技巧具有针对性。就拿状态池来说,状态池通常会用vector来实现,而像本题这种数据量很大(256万而不是基因管理的5万多),stl的低效率就会显现出来。
所有用到一些紫书上的高端技巧,一定要谨慎,最主要谨慎到这个技巧是否适合于本题,因为技巧具有针对性,可能出题者就已经想要你用这个技巧来做这道题。
如果你感觉出题者没有这个想法,你可能只是用一种比正常方法高端的做法做了这道题,脑子种想着要在写完之后blog里发这道题的高端做法,那基本上这个做法就是错的了。
毕竟noip级别接触到的题目,依然以求稳为主。这种题目重“抖机灵”而轻特定技巧。能用低端的方法解决就用低端方法,因为低端方法简单容易掌握,而高端方法你会自以为自己会了而难以面对各种特殊处理与突发情况。(如debug很久等)

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)a
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;

const int maxn = 350 + 10;
const int maxm = 120 + 4;
const int maxt = 40+2;

int n, m, A[maxn], c[4], d[maxt][maxt][maxt][maxt];

int main() {
    scanf("%d%d", &n, &m);
    _rep(i, 1, n) scanf("%d", &A[i]);
    int cc;
    _rep(i, 1, m) {
        scanf("%d", &cc);
        if (cc == 1) c[0]++;
        else if (cc == 2) c[1]++;
        else if (cc == 3) c[2]++;
        else c[3]++;
    }

    _rep(i, 0, c[0]) _rep(j, 0, c[1]) _rep(k, 0, c[2]) _rep(l, 0, c[3]) {
        int p = 1 + i * 1 + j * 2 + k * 3 + l * 4;
        int &ans = d[i][j][k][l];
        ans = A[p];
        if (i > 0) ans = max(ans, d[i - 1][j][k][l] + A[p]);
        if (j > 0) ans = max(ans, d[i][j - 1][k][l] + A[p]);
        if (k > 0) ans = max(ans, d[i][j][k - 1][l] + A[p]);
        if (l > 0) ans = max(ans, d[i][j][k][l - 1] + A[p]);
    }

    printf("%d\n", d[c[0]][c[1]][c[2]][c[3]]);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/icecab/article/details/81054491