ZOJ 3599 K倍动态减法游戏
下面的文字辅助理解来自http://blog.csdn.net/tbl_123/article/details/24884861
博弈论中的 K倍动态减法游戏,难度较大,参看了好多资料才懵懂!
此题可以看作 Fibonacci 博弈的扩展,建议没弄懂 Fibonacci博弈的先学那个,个人整理 http://blog.csdn.net/tbl_123/article/details/24033245 ;
而说扩展体现在数列不再是Fib数列,是根据 k 的值自行构造的,其它换汤不换药,具体构造方法如下:
这儿方便说明白,首先根据k的值分情况讨论:
1) 当 k = 1 时,必败态为 n = 2 ^ i, 因为我们把数按二进制分解后,拿掉二进制的最后一个1,那么对方必然不能拿走倒数第二位的1,因为他不能拿的比你多。你只要按照这个策略对方一直都不可能拿完。所以你就会赢。而当分解的二进制中只有一个1时,因为第一次先手不能全部取完,所以后手一定有办法取到最后一个1,所以必败!
举个例子,当 n = 6 = (110)时:
第一轮:先手第一次取最右边的1,即2个,此时还剩4(100)个,后手能取1或2个;
第二轮:假如上轮后手取的两个,先手再取两个直接赢了
假如后手取了一个,那么还剩三个,自己只能去1个,以后也只能取一个,所以必胜!
2) 当 k = 2 时,赤裸裸的Fibonacci博弈了,具体这儿不多说,自己再上述博客已写的很明白了。其实n经拆解后也可以表示成二进制的形式,用 k = 1时的方法来理解,比如 n = 11 = 7 + 3 + 1,可表示成 10101;
3) 当 k 取任意非零正值时,重点来了:
犹如Fibonacci博弈,我们首先要求一个数列,将n分解成数列中一些项的和,然后就可以按Fibonacci博弈的解决方法来完成,也可以按二进制的方法来理解,每次取掉最后一个1 还是符合上面的条件。
我们用a数组表示要被求的数列,b数组中的b[i]保存 a[0...i] 组合能够构造的最大数字。这儿有点难理解,所谓构造就是指n分解为Fib数相加的逆过程。举例说明,当k = 2 时,a[N]={1, 2, 3, 5, 8, 13, 21, 33....} (Fibonacci数组);那么b[3] 即 1、2、 3 能够构造的最大数字,答案是4,有点匪夷所思?或许你会问为什么不是5、6或者其它的什么,其实是这样的 ,4 能分解成 1+3 是没有争议的,但5能分解成2+3吗? 不能,因为5本身也是Fibonacci数;6虽然能分解,但不是分解成1+2+3,而是分解成1+5。
经过上述,我们知道b[i] 是 a[0...i] 能够构造出的最大数字,那么a[i +1] = b[i]+1;因为a数组(Fib数组)所存的数字都是不可构造的(取到它本身就是必败态),显然a[0...i]构造的最大数字 + 1 即为下一个不可构造的数字了(a[i + 1])。
然后关于b[i]的计算,既然是a[0...i]构造最大数字,那么 a[i]是一定要选用的(这儿需要一定的推理,a[i]构造数字时,相邻的j个是不能同时用的,就像上述的2、3不能构造出5一样,推理请自己完成),那么要选用的下一项只能递减寻找,直到找到 a[t] 满足 a[t] * K < a[i] ,而b[t]就是a[0...t]所能构造的最大数字,再加上a[i], 即为a[0...i]能构造的最大数字,于是b[i] = b[t] + a[i]。
求的数列后,之后的工作就简单了,跟Fibonacci博弈一样一样的,如果n=数列中的数,则必败,否则必胜;必胜时还要求输出第一步取法,其实就是分解的数列中最小的一个,将见代码。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
LL a[],b[];
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
LL N,M;
cin >> M >> N;
a[] = b[] = ;
int i = ,j = ;
while (N > a[i])
{
i++;
a[i] = b[i - ] + ;
while (a[j + ] * M < a[i]) j++;
if (a[j] * M < a[i]) b[i] = b[j] + a[i];
else b[i] = a[i];
}
LL ans;
if (N == a[i]) ans = N - i - ;
else ans = N - i;
cout << ans << endl;
}
return ;
}
ZOJ 3599 K倍动态减法游戏的更多相关文章
- uva 1567 - A simple stone game(K倍动态减法游戏)
option=com_onlinejudge&Itemid=8&page=show_problem&problem=4342">题目链接:uva 1567 - ...
- K倍动态减法游戏
题目:http://acm.hdu.edu.cn/showproblem.php?pid=2580 #include <iostream> #include <string.h> ...
- Poj-3922 A simple stone game(k倍动态减法)
题意: 游戏是这样的:两个玩家以一堆n个石头开始游戏.他们轮流从石堆里取石头,每次至少取一块.先走的人第一步最多可以拿n-1块石头.从那时起,一个玩家最多可以拿k倍于他的对手上次拿的石头.例如,如果一 ...
- zoj 3599 Game 博弈论
K倍动态减法游戏!!! 链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4683 代码如下: #include<ios ...
- k倍区间(解题报告)前缀和简单应用
测评地址 问题 1882: [蓝桥杯][2017年第八届真题]k倍区间 时间限制: 1Sec 内存限制: 128MB 提交: 351 解决: 78 题目描述 给定一个长度为N的数列,A1, A2, . ...
- 【Unity3D】Unity3D之 注册表动态存取游戏存档——PlayerPrefs类
[Unity3D]Unity3D之 注册表动态存取游戏存档--PlayerPrefs类 1.Unity3D提供了一个用于本地持久化保存与读取的类--PlayerPrefs.工作原理非常简单,以键值对的 ...
- 2017第八届蓝桥杯 K倍区间
标题: k倍区间 给定一个长度为N的数列,A1, A2, - AN,如果其中一段连续的子序列Ai, Ai+1, - Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间. ...
- 蓝桥杯试题 k倍区间(dp)
问题描述 给定一个长度为N的数列,A1, A2, ... AN,如果其中一段连续的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间. ...
- k倍区间
看大佬的代码看了半天,终于算是懂了 标题: k倍区间 给定一个长度为N的数列,A1, A2, … AN,如果其中一段连续的子序列Ai, Ai+1, … Aj(i <= j)之和是K的倍数,我们就 ...
随机推荐
- SetWindowPos,RegisterHotKey,GlobalAddAtom的用法
还以为SetWindowPos是给Frm的子框架间编写的,原来是给mainfrm写的,可以把你写的主窗口置顶,置底(看样子应该可以变成桌面了,还没试呢,才忙到现在...) 子窗口的遮挡可以使用窗口的样 ...
- ardupilot_gazebo仿真(四)
ardupilot_gazebo仿真(四) 标签(空格分隔): 未分类 Multi-MAV simulation 参考官网给出的multi-vehicle-simulation的方法 在每次打开sim ...
- Leetcode 679.24点游戏
24点游戏 你有 4 张写有 1 到 9 数字的牌.你需要判断是否能通过 *,/,+,-,(,) 的运算得到 24. 示例 1: 输入: [4, 1, 8, 7] 输出: True 解释: (8-4) ...
- Eureka搭建
Eureka搭建 一.Eureka基本框架搭建 pom.xml文件配置:主要是引入Eureka所依赖的jar包 <?xml version="1.0" encoding=&q ...
- CentOS 6.5 下安装redis
1.登录虚拟机后,直接输入命令:yum -y install redis 会出现一个错误: 是因为少了epel源, 2.运行:yum -y install epel-release 最后出现 Comp ...
- JavaSE复习(五)网络编程
客户端:java.net.Socket 类表示.创建Socket对象,向服务端发出连接请求,服务端响应请求,两者建立连接开始通信 服务端:java.net.ServerSocket 类表示.创建Ser ...
- Linux SPI总线和设备驱动架构之二:SPI通用接口层
通过上一篇文章的介绍,我们知道,SPI通用接口层用于把具体SPI设备的协议驱动和SPI控制器驱动联接在一起,通用接口层除了为协议驱动和控制器驱动提供一系列的标准接口API,同时还为这些接口API定义了 ...
- 算法(10)Subarray Sum Equals K
题目:在数组中找到一个子数组,让子数组的和是k. 思路:先发发牢骚,这两天做题是卡到不行哇,前一个题折腾了三天,这个题上午又被卡住,一气之下,中午睡觉,下午去了趟公司,竟然把namespace和cgr ...
- [剑指Offer] 22.从上往下打印二叉树
[思路]广度优先遍历,队列实现 class Solution { public: vector<int> PrintFromTopToBottom(TreeNode* root) { qu ...
- [洛谷P1892]团伙
题目大意:有n个人,关系为:朋友的朋友是朋友,敌人的敌人是朋友.如果是朋友就在一个团队内,是敌人就不在,现在给出一关系,问最多有多少团伙.题解:并查集,建反集,如果是朋友,就把他们的并查集合并:如果是 ...