P2964 [USACO09NOV]硬币的游戏A Coin Game (DP)

题意:n颗硬币 两个人从前往后按顺序拿

   如果上一个人拿了i颗 那么下一个可以拿1-2*i颗

   问先手能获得的最大收益

题解:比较典型的最大最小最大最小..DP了

   但是暴力做的话是n^3 所以就体现出了这个题的巧妙之处

   dp[i][j]表示拿到了第i颗上一个人拿了j颗

   dp[i][j]由 dp[i + k][k] k = 1,2...2 * j转移来

   dp[i][j - 1]由 dp[i + k][k] k = 1,2...2 * (j - 1)转移来

   有许多状态是一样的 所以dp[i][j-1]可以转移到dp[i][j] 再枚举两个新的状态

   显然要倒着dp

 

#include <bits/stdc++.h>
using namespace std;

int sum[2005];
int dp[2005][2005];

int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &sum[i]), sum[i] += sum[i - 1];

    for(int i = i; i <= n; i++) dp[n][i] = sum[n] - sum[n - 1];
    for(int i = n - 1; i >= 1; i--)
    {
        for(int j = 1; j <= n; j++)
        {
            dp[i][j] = dp[i][j - 1];
            int k = (j - 1) * 2 + 1;
            if(i + k <= n) dp[i][j] = max(dp[i][j], sum[n] - sum[i - 1] - dp[i + k][k]);
            else dp[i][j] = max(dp[i][j], sum[n] - sum[i - 1]);

            k++;
            if(i + k <= n) dp[i][j] = max(dp[i][j], sum[n] - sum[i - 1] - dp[i + k][k]);
            else dp[i][j] = max(dp[i][j], sum[n] - sum[i - 1]);
        }
    }
    printf("%d\n", dp[1][1]);
    return 0;
}
View Code

 

   

posted @ 2019-01-30 15:44  lwqq3  阅读(155)  评论(0编辑  收藏  举报