【2017沈阳网络赛】1006 hdu6199 gems gems gems 动态规划

来源:互联网 发布:淘宝打假吃货仅退款 编辑:程序博客网 时间:2024/06/02 04:55

Problem Description
Now there are n gems, each of which has its own value. Alice and Bob play a game with these n gems.
They place the gems in a row and decide to take turns to take gems from left to right. 
Alice goes first and takes 1 or 2 gems from the left. After that, on each turn a player can take k or k+1 gems if the other player takes k gems in the previous turn. The game ends when there are no gems left or the current player can't take k or k+1 gems.
Your task is to determine the difference between the total value of gems Alice took and Bob took. Assume both players play optimally. Alice wants to maximize the difference while Bob wants to minimize it.
 

Input
The first line contains an integer T (1T10), the number of the test cases. 
For each test case:
the first line contains a numbers n (1n20000);
the second line contains n numbers: V1,V2Vn. (100000Vi100000)
 

Output
For each test case, print a single number in a line: the difference between the total value of gems Alice took and the total value of gems Bob took.
 

Sample Input
131 3 2
 

Sample Output
4
 

题意:

给出一个数列,两个人轮流取数,最开始可以取1或2个,之后每一次可以取和前一次相同或者多1个。取完或者不足停止。先取的人希望差最大,后取的人希望差最小,两人都是最优策略。求最后的差。


思路:

设d[j][i][k],代表第j个人取第i个数时前一次取为k的最优解。对于j=0,希望差最大,对于j=1,希望差最小。

d[0][i][k]=max(d[1][i+k][k]+sum[i+k-1]-sum[i-1],d[1][i+k+1][k+1]+sum[i+k]-sum[i-1]);

d[1][i][k]=min(d[0][i+k][k]-sum[i+k-1]+sum[i-1],d[0][i+k+1][k+1]-sum[i+k]+sum[i-1]);

假设每次都取k+1,(1+k)*(2+k)/2<=n,k能达到的最大值kmax不超过sqrt(n*2)+1;
这题内存特别小,正常开数组会MLE。由于k不超过201,i跨度超过201时一定不会被使用到,我们用滚动数组的思想,对i取模。

////  main.cpp//  1006////  Created by zc on 2017/9/12.//  Copyright © 2017年 zc. All rights reserved.//#include <iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#define ll long longusing namespace std;const int N=22000;const int MOD=255;int d[2][256][210],sum[N];int main(int argc, const char * argv[]) {    int T,n,t;    scanf("%d",&T);    while(T--)    {        scanf("%d",&n);        sum[0]=0;        for(int i=1;i<=n;i++)        {            scanf("%d",&t);            sum[i]=sum[i-1]+t;        }        int maxk=(int)sqrt(n*2)+1;        memset(d,0,sizeof(d));        for(int i=n;i>0;i--)            for(int k=1;k<=maxk&&k+i-1<=n;k++)            {                d[0][i&MOD][k]=d[1][(i+k)&MOD][k]+sum[i+k-1]-sum[i-1];                d[1][i&MOD][k]=d[0][(i+k)&MOD][k]-sum[i+k-1]+sum[i-1];                if(k+i<=n)                {                    d[0][i&MOD][k]=max(d[0][i&MOD][k],d[1][(i+k+1)&MOD][k+1]+sum[i+k]-sum[i-1]);                    d[1][i&MOD][k]=min(d[1][i&MOD][k],d[0][(i+k+1)&MOD][k+1]-sum[i+k]+sum[i-1]);                }            }        printf("%d\n",d[0][1][1]);    }}

原创粉丝点击