hdu6199

来源:互联网 发布:中国工业企业数据库 编辑:程序博客网 时间:2024/06/14 15:54

沈阳网络赛1006
gems gems gems
题意是有n堆宝石(可能有负数),A和B从左到右拿宝石,A先手拿1或者2堆,假设某个人当前拿了k堆,那么下一个人只能拿k或者k+1堆,如果他取不了k堆宝石时,游戏结束。定义difference为A拿到的宝石数减去B拿到的宝石数,A想要其值最大化,B想要其值最小化,假设A和B都用最好的策略,那么这个最终的difference最大可以多大。

这个题目好像有原题,是cf上的一个题目Financiers Game
真的是一个非常好的题目,看似一个博弈题,其实没有一个必胜或者必败点,这里我们要用dp去解决,而且dp的状态也是非常的神奇。
首先我们考虑每次每个人的有两种选择,假设上一个人取了k堆,那么他这次能够取k或者k+1堆,有两种选择,那么我们可以考虑对这两种选择进行dp。
我们定义dp[0/1][i][j]表示第1/2个人在第i个数字取,且上一次对方取了j个时,第1/2个人能得到最好的结果(由于两个人想要的结果不一样,所以两个方程不同)。那么从这个状态出发,我们可以得到关于第一个人的方程

    dp[0][i][j] = max(Sum[i+j-1] - Sum[i-1] + dp[1][i+j][j] , Sum[i+j ] - Sum[i-1] + dp[1][i+j+1][j+1] ) ;//由于跟后面的宝石有关,我们方程从后往前转移

同理我们可以得到关于第二人的方程,这个状态中的j不会特别大,j*j/2<=n,j最大大概是200左右,但是在hdu上还是会爆空间,由于只跟后200个左右的状态有关,我们考虑用滚动数组的方式来储存dp

#include<cmath>#include<algorithm>#include<cstring>#include<string>#include<set>#include<map>#include<time.h>#include<cstdio>#include<vector>#include<list>#include<stack>#include<queue>#include<iostream>#include<stdlib.h>using namespace std;#define  LONG long longconst LONG    INF=0x3f3f3f3f;const int  MOD=1e9+ 7;const double PI=acos(-1.0);#define clrI(x) memset(x,-1,sizeof(x))#define clr0(x) memset(x,0,sizeof x)#define clr1(x) memset(x,INF,sizeof x)#define clr2(x) memset(x,-INF,sizeof x)#define EPS 1e-10LONG dp[2][310][235] ;LONG v[20100] ;LONG Sum[20100] ;int main(){    int n ;    int T ;    cin >> T ;    while(   T -- )    {        cin >> n  ;        Sum[0] = 0 ;        clr0(dp) ;        for(int i =1;i<= n ; ++ i)scanf("%lld",&v[i]) , Sum[i] = Sum[i-1] + v[i] ;        for(int i = n ; i >= 1 ; -- i)            for(int j = 1 ;j * j /2 <= i ; ++j)            {                if(i + j  == n+1)                {                    dp[0][i&255][j] = Sum[i+j-1] - Sum[i-1] ;                    dp[1][i&255][j] = - Sum[i+j-1] + Sum[i-1] ;                    break ;                }                dp[0][i&255][j] = max(dp[1][i+j&255][j] , dp[1][i+j+1&255][j+1] + v[i+j]) + Sum[i+j-1] - Sum[i-1] ;                dp[1][i&255][j] = min(dp[0][i+j&255][j] , dp[0][i+j+1&255][j+1] - v[i+j] ) - Sum[i+j-1] + Sum[i-1] ;            }        cout<<dp[0][1][1]<<endl;    }    return 0 ;}
原创粉丝点击