博弈论+dp——洛谷P2964 [USACO09NOV]硬币的游戏A Coin Game

https://daniu.luogu.org/problem/show?pid=2964
本来博弈论就不懂,现在套上dp,直接萎了;
题解都看了半天;
我们搞一个f[i][j]表示还剩1~i的时候,上一个人选了j个;
显然i=n的时候是最开始,就是一个都没取;
现在我们倒着dp,所以一开始我们的读入也要倒着读;
关于这个f[i][j],它代表一个选手的状态,所以到底是先手还是后手我们不知道;
但是答案显然就是f[n][1];
就是说现在还剩1~n的物品(就是一开始的状态),上一个人取1个,显然这一次我们可以取1或2个,这个和我们一开始题目要求的状态是一样的;
那么怎么求f[i][j]呢?
那我们枚举现在要拿k个;
f[i][j]=max(f[i][j],sum[i]-f[i-k][k]);
因为f[i][j-1]已经算了一大片了,所以k只要枚举j*2-1和j*2就可以了;

#include
#include
#include
#include
#define Ll long long
using namespace std;
int f[2005][2005],a[2005];
int n;
int main()
{
    scanf("%d",&n);
    for(int i=n;i;i--)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)a[i]=a[i-1]+a[i];
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++){
        f[i][j]=f[i][j-1];
        int k=j*2;
        if(i>=k)f[i][j]=max(f[i][j],a[i]-f[i-k][k]);
        k=j*2-1;
        if(i>=k)f[i][j]=max(f[i][j],a[i]-f[i-k][k]);
    }
    printf("%d",f[n][1]);
}

你可能感兴趣的:(奇怪dp,博弈论)