HDU 6199 gems gems gems(dp)

Description

nn个石子,第i个石子分数为aiaiAliceAliceBobBob轮流取石子,AliceAlice先手,第一次AliceAlice可以拿左边的一个石子或两个石子,假设上一轮对手拿了kk个石子,这一轮就可以拿左边的k个石子或k+1k+1个石子,当石子不够取时游戏结束,问游戏结束时AliceAlice得分与BobBob得分之差的最大值,游戏过程中AliceAlice采取使得分差尽可能大的方案,BobBob采取使得分差尽可能小的方案

Input

第一行一整数TT表示用例组数,每组用例首先输入一整数n表示石子个数,之后输入nn个整数a1,...,an表示这nn个石子的分数(1T10,1n2000,105ai105)

Output

输出AilceAilceBobBob的分差

Sample Input

1
3
1 3 2

Sample Output

4

Solution

dp[0/1][i][j]dp[0/1][i][j]表示Alice/BobAlice/Bob从第ii个石子开始取且上一轮对手取了j个最后可以得到的最大分差,以si=j=1iajsi=∑j=1iaj,根据当前步取jj个或j+1个石子有转移

dp[0][i][j]=max(si+j1si1+dp[1][i+j][j],si+jsi1+dp[1][i+j+1][j+1])dp[0][i][j]=max(si+j−1−si−1+dp[1][i+j][j],si+j−si−1+dp[1][i+j+1][j+1])

dp[1][i][j]=min(si1si+j1+dp[0][i+j][j],si1si+j+dp[0][i+j+1][j+1])dp[1][i][j]=min(si−1−si+j−1+dp[0][i+j][j],si−1−si+j+dp[0][i+j+1][j+1])

注意到第kk轮最少也取了k(k+1)2个石子,故j2nj≤2n,大约200200左右,故第三维200200即可,第二维滚动一下

由于先手可以取一个或两个石子,可以认为先手之前其对手取了一个分数为00的石子,故答案为dp[0][1][1]

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
#define maxn 20005
int dp[2][255][255],T,n,a[maxn],sum[maxn];
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
        memset(dp,0,sizeof(dp));
        int m=(int)sqrt(2.0*n+1),mod=233;
        for(int i=n;i>=1;i--)
            for(int j=m;j>=1;j--)
                if(i+j-1<=n)
                {
                    dp[0][i%mod][j]=sum[i+j-1]-sum[i-1]+dp[1][(i+j)%mod][j];
                    dp[1][i%mod][j]=sum[i-1]-sum[i+j-1]+dp[0][(i+j)%mod][j];
                    if(i+j<=n)
                    {
                        dp[0][i%mod][j]=max(dp[0][i%mod][j],sum[i+j]-sum[i-1]+dp[1][(i+j+1)%mod][j+1]);
                        dp[1][i%mod][j]=min(dp[1][i%mod][j],sum[i-1]-sum[i+j]+dp[0][(i+j+1)%mod][j+1]);
                    }
                }
        printf("%d\n",dp[0][1][1]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值