• BZOJ_2017_[Usaco2009 Nov]硬币游戏_博弈论+DP


    BZOJ_2017_[Usaco2009 Nov]硬币游戏_博弈论+DP

    Description

    农夫约翰的奶牛喜欢玩硬币游戏,因此他发明了一种称为“Xoinc”的两人硬币游戏。 初始时,一个有N(5 <= N <= 2,000)枚硬币的堆栈放在地上,从堆顶数起的第I枚硬币的币值为C_i (1 <= C_i <= 100,000)。 开始玩游戏时,第一个玩家可以从堆顶拿走一枚或两枚硬币。如果第一个玩家只拿走堆顶的一枚硬币,那么第二个玩家可以拿走随后的一枚或两枚硬币。如果第一个玩家拿走两枚硬币,则第二个玩家可以拿走1,2,3,或4枚硬币。在每一轮中,当前的玩家至少拿走一枚硬币,至多拿走对手上一次所拿硬币数量的两倍。当没有硬币可拿时,游戏结束。 两个玩家都希望拿到最多钱数的硬币。请问,当游戏结束时,第一个玩家最多能拿多少钱呢?

    Input

    第1行:1个整数N

    第2..N+1行:第i+1行包含1个整数C_i

    Output

    第1行:1个整数表示第1个玩家能拿走的最大钱数。

    Sample Input

    5
    1
    3
    1
    7
    2

    Sample Output

    9

    HINT

    样例说明:第1个玩家先取走第1枚,第2个玩家取第2枚;第1个取走第3,4两枚,第2个玩家取走最后1枚。


    设f[i][j]表示还剩i枚硬币,上一个人拿了j枚硬币,到最后的最大收益。

    先手后手转移相同,f[i][j]=f[i-k][k] (k<=min(2*j,i)),直接DP是$O(n^3)$的。

    发现每次j增加时对k的影响只有2*j-1和2*j,再判断一下与i的关系即可。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 2050
    int f[N][N],n,s[N],a[N];
    int main() {
        scanf("%d",&n);
        int i,j;
        for(i=1;i<=n;i++) {
            scanf("%d",&a[i]);
        }
        for(i=n;i>=1;i--) s[i]=s[i+1]+a[i];
        for(i=1;i<=n;i++) {
            for(j=1;j<=n;j++) {
                f[i][j]=f[i][j-1];
                if(2*j-1<=i) f[i][j]=max(f[i][j],s[n-i+1]-f[i-(2*j-1)][2*j-1]);
                if(2*j<=i) f[i][j]=max(f[i][j],s[n-i+1]-f[i-2*j][2*j]);
            }
        }
        printf("%d
    ",f[n][1]);
    }
    
    
  • 相关阅读:
    求s=a+aa+aaa+aaaa+aa...a的值,其中a是一个数字。
    getchar函数
    计算机网络04-ip与子网划分
    计算机网络03-传输层、可靠数据传输、UDP与TCP
    计算机网络02-应用层(http、email、dns)
    游戏-图形学学习路线
    markDown 入门
    webpack 入门级 傻瓜式教学
    npm 切换 cnpm 切换淘宝镜像源
    vue 父组件在接收子组件的同时传递一个当前的数据
  • 原文地址:https://www.cnblogs.com/suika/p/9219535.html
Copyright © 2020-2023  润新知