NOIP2010 乌龟棋

传送门

这题一开始有个非常朴素的想法,五维DP,分别记录当前走到了哪,以及这四种牌各用了多少张。不过这样的话不仅MLE还TLE……

但是其实如果知道现在用什么牌的话,你走到哪是已知的,而且题目还保证走到最后牌刚好打完,所以第一维记录走到哪没什么用。

所以可以压成四位DP,之后就可以过了。

看一下代码。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
using namespace std;
typedef long long ll;
const int M = 100005;
const int N = 10000005;
 
int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
    if(ch == '-') op = -1;
    ch = getchar();
    }
    while(ch >='0' && ch <= '9')
    {
    ans *= 10;
    ans += ch - '0';
    ch = getchar();
    }
    return ans * op;
}

int n,m,sum[5],a[505],dp[45][45][45][45],z;

int main()
{
    n = read(),m = read();
    rep(i,1,n) a[i] = read();
    rep(i,1,m) z = read(),sum[z]++;
    dp[0][0][0][0] = a[1];
    rep(i,0,sum[1])
    rep(j,0,sum[2])
    rep(p,0,sum[3])
    rep(q,0,sum[4])
    {
    int d = 1 + i + (j << 1) + (p << 1) + p + (q << 2);
    if(i > 0) dp[i][j][p][q] = max(dp[i][j][p][q],dp[i-1][j][p][q] + a[d]);
    if(j > 0) dp[i][j][p][q] = max(dp[i][j][p][q],dp[i][j-1][p][q] + a[d]);
    if(p > 0) dp[i][j][p][q] = max(dp[i][j][p][q],dp[i][j][p-1][q] + a[d]);
    if(q > 0) dp[i][j][p][q] = max(dp[i][j][p][q],dp[i][j][p][q-1] + a[d]);
    }
    printf("%d\n",dp[sum[1]][sum[2]][sum[3]][sum[4]]);
    return 0;
}

 

posted @ 2018-10-29 21:16  CaptainLi  阅读(122)  评论(0编辑  收藏  举报