背景

农民John的牛喜欢玩硬币,所以John就为它们发明了一个新的两人硬币游戏,叫做Xoinc。

描述

最初地面上有一堆n个硬币(5<=n<=2000),从上面数第i个硬币的价值为C_i(1<=C_i<=100000);

游戏开始后,A先取一枚或两枚硬币。如果A取了一枚,那么B可以继续取一枚或两枚;如果A取了两枚,那么B可以取一到四枚硬币。每次都只能从最上面取。每一次,当前取硬币的人都至少取一枚硬币,最多可以取他的对手上一次取硬币数目的两倍。当没有硬币可取的时候,游戏就结束了。

然后,他们就可以用得到的硬币向John买东西,当然,他们游戏的目的就是要尽可能使自己得到的硬币价值更大。现在你的任务是,求出在两个人都想得到更大价值的情况下,游戏结束后,第一个人最多能得到的硬币价值。

输入格式

第1行: 一个整数,N(5<=N<=2000)。

第2到n+1行: 第 i+1 行代表从上数第i枚硬币的价值。

输出格式

一行:一个数字,第一个人能得到的最大价值

测试样例1

输入






2

输出

9

备注

usaco nov09 Ag 
translated by pricez

思路集合

解题思路
首先明确这是一题DP题目
那么不难发现几个必须枚举的状态
1、对方在上一轮取了几个(这个直接影响我方这回合取的数目)
2、当前还剩多少个可以取
3、我方这回合取了多少个
接着
假设上回合对方拿走了J个后还剩I个可供我们这回合拿取,那么可以推出我们能拿的硬币数的范围在1~2*J之间则可以列出
F[I,J]:=MAX(SUM[I]-F[I-K,K]);(1<=K<=2*J)
其中SUM[I]表示剩下的I个硬币的总面值
K表示我当前这回合拿了多少个
因为双方都是最优的取法来取
所以F[I-K,K]表示的就是对手在我拿走K个硬币还剩下I-K个硬币的情况他最多能取的面值大小
因而SUM[I]-F[I-K,K]表示的意义就是我在剩下的硬币中能取得的最多的面值大小
初始状态是F[0,1~N]=0;
末状态是F[N,1]

理解了上面的方程后
可以看出方程的时间复杂度就是O(N^3)显然会超时
这时候就需要优化
我们观察
F[I,J]的方程与F[I,J-1]的方程
可以发现
F[I,J-1]所枚举的所有状态在F[I,J]时又枚举了一遍,明显这是多余的
可以看出F[I,J]比F[I,J-1]多枚举的只有SUM[I]-F[I-(2*J-1),2*J-1]和SUM[I]-F[I-2*J,2*J]两项
所以方程可以改写成
F[I,J]:=MAX(F[I,J-1],MAX(SUM[I]-F[I-(2*J-1),2*J-1],SUM[I]-F[I-2*J,2*J]));
这样就优化到O(N^2)了
基本调试清楚下就可以AC了
---------------------
其实不需如上优化
第一个方程+单调队列足以AC

 
转载:

我们发现,每一个阶段都由上一个玩家决定的,即别人怎么拿限制了我怎么拿,那么

设状态为f(i, j)表示剩余i个硬币,上次拿了j个硬币,注意,是上一次!

f(i, j)=max{sum(1, i)-f(i-k, k)} 1<=k<=2*j

这点可以参照前边一题的dp博弈

sum(1, i)包含了2重意思,即sum(1, i-k), sum(i-k+1, i),前者是之前局面的和,后者是玩家所得的价值

而f(i-k, k)的意思就是根据上一次所拿硬币j限制了我这次拿硬币k,而这个状态就表示我这次拿了k个之后还剩与i-k个,而且是从我这个状态k个限制了它所拿硬币。

然后注意读入是倒序即可

但是这样做状态是n^2,转移n,显然2000的数据tle。

那么我们要优化

我们来看看f(10,1)的情况。

在这里,我们发现f(8,2)和f(8,1)的区别就是比其多了2条路,所以我们完全能想到以下方法。

将 除了自己特有的两条路保留后,另两条路舍去,直接连到f(8,1)的最优解上,这样就能将时间复杂度优化为O(n^2),这样的话,我们的状态转移方程可 以写为f(x,y)=Max{ f(x,y-1),sum[x]-Min{f(x-(2*y-1),2*y-1),f(x-2*y,2*y)} }

附不懂的代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int N,a[],f[][],sum[];
int main(){
// freopen("01.txt","r",stdin);
scanf("%d",&N);
for(int i=N;i>;i--)
scanf("%d",&a[i]);
for(int i=;i<=N;i++)
sum[i]=sum[i-]+a[i]; for(int i=;i<=N;i++)
for(int j=;j<=N;j++){
f[i][j]=f[i][j-];//自己特有的两条路保留,直接连到f(i,j-1)的最优解上
if(i-(j<<)>=)
f[i][j]=max(f[i][j],sum[i]-f[i-(j<<)][j<<]);
if(i-((j<<)-)>=)
f[i][j]=max(f[i][j],sum[i]-f[i-((j<<)-)][(j<<)-]);
}
printf("%d\n",f[N][]);
return ;
}

TYVJ P1075 硬币游戏 Label:dp的更多相关文章

  1. tyvj P1075 - 硬币游戏 博弈DP

    P1075 - 硬币游戏 From price    Normal (OI)总时限:10s    内存限制:128MB    代码长度限制:64KB 背景 Background 农民John的牛喜欢玩 ...

  2. 【BZOJ】2017: [Usaco2009 Nov]硬币游戏(dp+神题+博弈论)

    http://www.lydsy.com/JudgeOnline/problem.php?id=2017 这题太神了,我想了一个中午啊 原来是看错题一直没理解题解说的,一直以为题解是错的QAQ “开始 ...

  3. bzoj 2017: [Usaco2009 Nov]硬币游戏【dp】

    废了废了,一个小dp都想不出来 把c数组倒序一下,变成1在最下,设f[i][j]为某一人取完j个之后还剩1~i的硬币,转移的话应该是f[i][j]=max(s[i]-f[i-k][k]),就是1~n的 ...

  4. BZOJ 4820 [Sdoi2017]硬币游戏 ——期望DP 高斯消元

    做法太神了,理解不了. 自己想到的是建出AC自动机然后建出矩阵然后求逆计算,感觉可以过$40%$ 用一个状态$N$表示任意一个位置没有匹配成功的概率和. 每种匹配不成功的情况都是等价的. 然后我们强制 ...

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

    BZOJ_2017_[Usaco2009 Nov]硬币游戏_博弈论+DP Description 农夫约翰的奶牛喜欢玩硬币游戏,因此他发明了一种称为“Xoinc”的两人硬币游戏. 初始时,一个有N(5 ...

  6. 【BZOJ4820】[Sdoi2017]硬币游戏 AC自动机+概率DP+高斯消元

    [BZOJ4820][Sdoi2017]硬币游戏 Description 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数多谁胜利.大家纷纷觉得这个游戏非常符合同学们的特色,但只是扔硬 ...

  7. 4820: [Sdoi2017]硬币游戏

    4820: [Sdoi2017]硬币游戏 链接 分析: 期望dp+高斯消元. 首先可以建出AC自动机,Xi表示经过节点i的期望次数,然后高斯消元,这样点的个数太多,复杂度太大.但是AC自动机上末尾节点 ...

  8. [BZOJ4820]硬币游戏 KMP+高斯消元

    4820: [Sdoi2017]硬币游戏 Time Limit: 10 Sec  Memory Limit: 128 MB Description 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的 ...

  9. [BZOJ2017][Usaco2009 Nov]硬币游戏

    Description 农夫约翰的奶牛喜欢玩硬币游戏,因此他发明了一种称为“Xoinc”的两人硬币游戏. 初始时,一个有N(5 <= N <= 2,000)枚硬币的堆栈放在地上,从堆顶数起 ...

随机推荐

  1. 基本二叉搜索树的第K小元素

    #include<stdio.h> #include<stdlib.h> typedef struct node *btlink; struct node { int data ...

  2. IP地址,子网掩码,默认网关

    IP地址: 是给每个连接在Internet上的主机分配的一个32bit地址. 地址有两部分组成,一部分为网络地址,另一部分为主机地址. IP地址分为A.B.C.D.E 5类.常用的是B和C两类. 网络 ...

  3. Python DBUtils

    1 简介 DBUtils是一套Python数据库连接池包,并允许对非线程安全的数据库接口进行线程安全包装.DBUtils来自Webware for Python. DBUtils提供两种外部接口: P ...

  4. 使用WebDriver遇到的那些坑(转)

    http://www.huangbowen.net/blog/2013/06/25/practice-of-webdriver/ 在做web项目的自动化端到端测试时主要使用的是Selenium Web ...

  5. c/c++指针总结[pointer summary]

    [本文链接] http://www.cnblogs.com/hellogiser/p/pointer-summary.html 1.指针注意事项 (1). 指针类型字符串不容许修改 char *str ...

  6. 百度编辑器ueditor每次编辑后多一个空行的解决办法

    用ueditor进行编辑文章时,每次编辑后文章前面都会多出一个空行. <script id="editor" type="text/plain" styl ...

  7. 【转】kettle 的内存设置及输出日志的时间类型

    本文转载自:http://blog.csdn.net/dqswuyundong/archive/2010/10/19/5952004.aspx 设置kettle的内存 REM ************ ...

  8. iOS UIDatePicker frame改变问题

    这种方法不行: pickerCtl = UIDatePicker(frame:pickerFrame) 但是这种却行 pickerCtl = UIDatePicker() pickerCtl!.fra ...

  9. Greedy:Cleaning Shifts(POJ 2376)

      牛的大扫除 题目大意:农夫有N只牛,这些牛要帮助打扫农舍,这些牛只能打扫固定位置(千万要注意这个位置不是连续的),每一段区间必须至少有一只牛打扫,问你至少需要多少只牛?(如果区间不能完全被覆盖,则 ...

  10. 【linux】awk的使用

    教程来自:http://www.runoob.com/linux/linux-comm-awk.html 教程中的例子很好,可以有助于快速上手awk.但是里面的细节介绍的并不清楚. 问题1:什么时候写 ...