码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj2017[Usaco2009 Nov]硬币游戏*

时间:2016-09-03 22:36:43      阅读:273      评论:0      收藏:0      [点我收藏+]

标签:

bzoj2017[Usaco2009 Nov]硬币游戏

题意:

初始时,一个有N枚硬币的堆栈放在地上,每枚硬币都有一个价值。开始玩游戏时,第一个玩家可以从堆顶拿走一枚或两枚硬币。之后每一轮中,当前的玩家至少拿走一枚硬币,至多拿走对手上一次所拿硬币数量的两倍。当没有硬币可拿时,游戏结束。 两个玩家都希望拿到最多钱数的硬币。求第一个玩家最多能拿多少钱。n≤2000。

题解:

首先有dp方程:f[i][j][0]=max(f[i][k][1]+sum(i-k,i)),1≤k≤min(j*2,i),f[i][j][1]=min(f[i][k][0]),1≤k≤min(j*2,i)。

然而这样会超时。发现所以f[i][k][1]的最大值实际上是f[i][j*2][1]、f[i][j*2-1][1]、f[i][j-1][0]的最大值,f[i][k][0]的最小值也是f[i][j*2][0]、f[i][j*2-1][0]、f[i][j-1][1]的最小值。故可以把dp优化到O(n^2)可过。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define maxn 2010
 6 using namespace std;
 7 
 8 inline int read(){
 9     char ch=getchar(); int f=1,x=0;
10     while(ch<0||ch>9){if(ch==-)f=-1; ch=getchar();}
11     while(ch>=0&&ch<=9)x=x*10+ch-0,ch=getchar();
12     return f*x;
13 }
14 int a[maxn],sm[maxn],f[maxn][maxn][2],n;
15 int main(){
16     n=read(); inc(i,1,n)a[i]=read(); for(int i=n;i>=1;i--)sm[n-i+1]=sm[n-i]+a[i];
17     inc(i,1,n)
18         inc(j,1,n){
19             f[i][j][0]=j>1?f[i][j-1][0]:0; int k;
20             k=2*j-1; if(k<=i)f[i][j][0]=max(f[i][j][0],f[i-k][k][1]+sm[i]-sm[i-k]);
21             k=2*j;  if(k<=i)f[i][j][0]=max(f[i][j][0],f[i-k][k][1]+sm[i]-sm[i-k]);
22             f[i][j][1]=j>1?f[i][j-1][1]:0x3fffffff;
23             k=2*j-1; if(k<=i)f[i][j][1]=min(f[i][j][1],f[i-k][k][0]);
24             k=2*j; if(k<=i)f[i][j][1]=min(f[i][j][1],f[i-k][k][0]);
25         }
26     printf("%d",f[n][1][0]); return 0;
27 }

 

20160830

bzoj2017[Usaco2009 Nov]硬币游戏*

标签:

原文地址:http://www.cnblogs.com/YuanZiming/p/5838077.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!