HDU4701_Game
很有意思,很好的一个题目。
题目的意思是两个人初始状态分别有A和B元,现在有N件可买的商品。两人轮流买,商品必须从左到右买过去,一次可以买若干个。第一个无法买到商品的人输。
一看就知道是博弈题目,但是这并不是什么模型式的博弈题目,其实是转化成递推来做的。
一开始我也不知道到底应该怎么来考虑这个问题,于是就按照博弈的思想用Mex的思路去写这个题目,直到我T了发。
后来在网上看到神牛们写的博客后才发现正确的解法。
其实这个问题应该是这样来考虑的。
首先告诉了你两个人初始的钱数,那么总共的钱数是确定。在买完若干件商品后,一部分的钱数已经花在了买商品上面(先不管是谁买的),另一部分的钱还分别留在两个人的手中。这样如果我们知道当前买完了某件商品后其中一个人的剩余的钱数,那么我们可以根据总钱数不变来推出另一个人手中的钱数。
同时,如果在买某一件商品开始是,ALICE手中只要有x元就有了必胜的策略,那么他手中的钱数如果大于x,显然就也是必胜咯。
有了这两点,我们可以来个递推,解决这个问题。
状态f[i]表示在买第i件商品前,只要先手的人的钱数不少于f[i],那么他就有必胜的策略。
什么意思呢?
我们首先看看,A+B即总钱数,最多能买到多少件商品,显然后面的商品都是没有用的。
然后,对于可买的最后的那件商品n,f[n]=a[n]; 因为根据总钱数,只要他能够买掉最后一件商品,下一个人一定无钱购买后面的商品。
接下来就是从i递推到i-1了。
首先从i-1到i可能有两种情况:
一、第i-1个商品和第i个商品是同一个人购买,这说明要是在购买i-1个商品的时候就有必胜的策略,那么此时他手里的钱数必须不小于a[i-1]+f[i](买完第i-1个商品后,必须至少还剩下f[i]的钱)。
二、第i-1个商品和第i个商品不是同一个人购买,这说明前一个人在购买了i-1个商品后,留下了一个必败态给下一个人去购买第i个商品,这里我们知道对于第i个商品,其必败态就是钱数不足f[i]。这样根据总价值的关系就可以推出这种情况下的f[i-1]了。
综合上面的两种情况,我们知道f[i]就是两种情况中的最小值。
这样逐一递推,到达求出f[1],显然我们只要把f[1]和A比较大小,就可以得出谁胜谁负了。
题目很有意思,以前没做过这种类型的题目。赞一个。
#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 1000100
#define ll long long
using namespace std; ll n,m,A,B,l,r,mid,tot;
ll a[maxn],f[maxn],sum[maxn]; ll find()
{
l=,r=n;
if (A+B>=sum[n]) return n;
while (l<r)
{
mid=(l+r)>>;
if (sum[mid]>A+B) r=mid;
else l=mid+;
}
return l-;
} int main()
{
while (scanf("%I64d%I64d%I64d",&n,&A,&B)!=EOF)
{
sum[]=;
tot=A+B;
for (ll i=; i<=n; i++) scanf("%I64d",&a[i]),sum[i]=sum[i-]+a[i];
if (A<sum[])
{
printf("BOB\n");
continue;
}
if (A>=sum[n])
{
printf("ALICE\n");
continue;
}
n=find();
f[n]=a[n];
if (tot-sum[n-]-f[n]>=a[n]) f[n]=tot-sum[n-]-a[n]+; for (int i=n-; i>=; i--)
{
f[i]=a[i]+f[i+];
if (tot-sum[i-]-f[i+]+<f[i]) f[i]=tot-sum[i-]-f[i+]+;
} if (f[]>A) printf("BOB\n");
else printf("ALICE\n");
}
return ;
}
HDU4701_Game的更多相关文章
随机推荐
- 20155328 实验四 Android程序设计 实验报告
20155328 实验四 Android程序设计 第24章 初识Android 提交点1:完成HelloWorld并显示自己的学号 安装Android Studio后,创建了属于自己的Project( ...
- 《Java程序设计》课堂实践内容总结
<Java程序设计>课堂实践内容总结 实践一 要求 修改教材P98 Score2.java, 让执行结果数组填充是自己的学号: 提交在IDEA或命令行中运行结查截图,加上学号水印,没学号的 ...
- day5 二值化
1.otsu二值化 # coding=utf-8 import cv2 import numpy as np from matplotlib import pyplot as plt #1.读入图像 ...
- ptyhon基础篇 day1
1.变量 print('helloworld!') name = 'alex' name2 = 'jack' print(name,name2) 2.input #用户输入 username = in ...
- CF 1083 C. Max Mex
C. Max Mex https://codeforces.com/contest/1083/problem/C 题意: 一棵$n$个点的树,每个点上有一个数(每个点的上的数互不相同,而且构成一个0~ ...
- SRM First Problem && SRM 638 250pts NamingConvention
NamingConvention 题意: 给一个字符串,删掉所有的'_',然后将‘_'后的第一个字符改成大写. 代码: #include<bits/stdc++.h> using name ...
- Pomelo.AspNetCore.TimedJob 允许依赖注入
public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStar ...
- tp框架-------验证码
验证码我们一般很常见,在注册或登录时,都可以用的到,下面我们就来看看它的代码和用法 加验证码是为了防止表单攻击的一种方式,为了我们的程序更加的安全 在tp框架中它自带了一个验证码的类,我们先来看一下 ...
- 搞懂.NET Framework 历史版本(2017年)
最近被.NET平台各种名词.以及各种版本弄得有些疑惑,开发和部署,对于开发平台版本选择是个基本问题,因此,花了些时间,学习汇总了有关.NET版本演进的历史. .NET简介 这个平台相信我们都知道,不过 ...
- Android线程管理(三)——Thread类的内部原理、休眠及唤醒
线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...