2017沈阳网络赛 HDU 6199 gems gems gems

题意 : 两个人轮流拿物品,每一个物品都有一个价值,第 i 次拿 k 个那么 第 i + 1 次 可以拿 k + 1 或者 k 个。每个人都采取最有策略问你最后两个人的差。

题解 : 首先我们发现每一次只能拿k 或者 k + 1 个,这样的话我们就可以发现这样的一个性质 若一第 i 个开始拿,这一次拿的个数不能超过 sqet (2 * i) + 1个。这样的话我们就可以定义dp 状态了 dp (i,j,k) 表示从第 k 个人从 第 i个开始拿 ,拿走 j 个  第一个人拿走的减去第二个人所拿走的差的值  k 只有 0 1两个值分别表示第一个人拿还是第二个人拿,每个人的目的不一样所以dp的转移稍微有点不同,我们发现dp的状态是从后往前转移的这一点很关键。

dp(i,j,0) = min (dp(i + j,j,1),dp[i + j,j + 1,1)) + sum[i + j - 1] - sum[i - 1];

dp(i,j,1) = max (dp(i + j,j,0),dp[i + j,j + 1,0) - (sum[i + j - 1] - sum[i - 1]); sum 是前缀和

因为前面的人要受到选完之后要收到后面的那个人的控制并且 0 的目的是使得这个答案尽量大,1的目的是使得答案尽量小 所以两个的dp转移有所不同类似于敌对搜索的状态。


还有这个题目竟然卡内存....... 表示无语........  可以是用指针解决或者第一维压缩一下 也可以的代码里没有压缩内存 。


#include <iostream>

#include <algorithm>

#include <cstdio>

#include <cstring>

#include <cmath>

using namespace  std;

const int maxn = 20005;

int dp[maxn][202][2] = {0};

int pre[maxn] = {0};

int n;

int main () {

    ios_base :: sync_with_stdio(false);

    int T;

    cin >> T;

    while (T--) {

        cin >> n;

        memset (dp,0,sizeof(dp));

        pre[0] = 0;

        for (int i = 1;i <= n; ++ i) {

            cin >> pre[i];

            pre[i] += pre[i - 1];

        }

        pre[n + 1] = pre[n + 2] = pre[n];

        for (int i = n;i >= 1;-- i) {

            int u = sqrt  (i + i) + 1;

            int remain = n - i + 1;

            int lim = min (remain,u);

            for (int j = 1;j <= lim; ++ j) {

                if (j == remain) {

                    dp[i][j][0] = pre[i + j - 1] - pre[i - 1];

                    dp[i][j][1] = pre[i - 1] - pre[i + j - 1];

                }

                else {

                    if (i + j + j - 1 <= n) {

                        dp[i][j][0] = dp[i + j][j][1];

                        dp[i][j][1] = dp[i + j][j][0];

                        if (i + j + j <= n) {

                            dp[i][j][0] = min (dp[i][j][0],dp[i + j][j + 1][1]);

                            dp[i][j][1] = max (dp[i][j][1],dp[i + j][j + 1][0]);

                        }

                    }

                    dp[i][j][0] += (pre[i + j - 1] - pre[i - 1]);

                    dp[i][j][1] -= (pre[i + j - 1] - pre[i - 1]);

                }

            }

        }

//        cout << dp[1][1][0] << ' ' << dp[1][2][0] << ' ';

        cout << max (dp[1][1][0],dp[1][2][0]) << endl;

    }

    return 0;

}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值