POJ 3922A Simple Stone Game
题目链接 A Sample Stone Game
题目大意:给定n,k,表示最初时有n个石头,两个人玩取石子游戏,第一个人第一次可以取1~n-1个石头,后面每个人最多可以拿走前面一个人拿走的个数的K倍,当有一个人可以一次性全部拿走时获胜。问两人都在不失误的情况下,先拿着有没有必胜局势。有的话求他第一次最少该取多少个。
思考过程:
首先讨论k=1的情况,我们可以把一个数n(石子的个数),写为二进制下的表示,那先者取走最后一个1,那后者必然不能取走比它高一位的1,那么先拿者一定会赢,当然如果n本来就是2^i形式,那么先拿着当然不能拿走最后一个1,这样的话,石子就会取完了,所以这时先取者必输。举个例子来说 N = 20,他的二进制表示就是
1、10100 先拿者A拿走最后一个1(相当于拿走4个)n变为
2、10000 这时后取者B只能拿m=1,2,3,4个,假如是拿走3个,那么n变为
3、01101 这样A又可以取走最后一个1,。
... ... 这样继续下去,当这个数n变为1时
00001, 最后一个1一定还是A拿走的,所以A必赢
而其实第2步中,不管B拿走多少个(即不管m是多少m = 1 or 2 or 3 or 4),在她之后的那个人又一定可以取走最后一个1(即取走x = (1<<y)),且这个数x一定小于等于m(定理1),这样的话B永远也不可能取完。
而如果最初,n就等于2^j,二进制就是 10000... 那A自然不可能取走最后一个1(那就取了n个了),这样的话A取走一个m剩下的数就转化为上面,第1步中的形式了,那B一定就是必赢了
然后是k=2时,由定理2可以知道任何一个非菲波拉契数n都可以写为多个两两不相邻的斐波拉契数的和,这样的话先取者A先拿走一个小的斐波拉契数x,那后取者就无法取到另一个较大的菲波拉契数y(因为x与y不相邻,所以y>2*x)。这样又给A留下了一个非斐波拉契数,一直递归下去,A一定就是赢者。
但同时,如果A最初面临的就是一个菲波拉契数Fn,但是Fn只能写为Fn-1 + Fn-2,如果取Fn-2,由于Fn-1 < 2 * Fn-2,所以B可以取完,如果取其他任意一个非斐波拉契数m,B得到的那剩下的数Fn-m就相当于上面的A最初面临的n,也就是说B必赢。
而对于一般的K,由上面的思路,我们的目的就是要让n写为一些数的和n1 + n2 + ...+np,而且它们两两相邻之间的倍数关系应该大于k,这样的话我们先者A取走小一点的数n1,后者B必然不能取走n2,就给A留下了一些数,这样的话B自然不能取完所以A获胜。
在解题时,那我们就应该求出某个数列a[],这个数列要满足任何一个不再这个数列里面的数都可以用这个数列里的(满足前提条件前一项的k倍小于后一项的)多项的和表示(就好似定理2中任何一个数都可以写为多个个不连续的菲波拉契数(不连续就是相当于前一个的k=2倍小于后一个数)的和是同样的原理)。
而为了要求出这个数组a,我们引入另一个数组b[],b[i]表示a[0],a[1]...a[i]可以找到两项a[x]和a[y]满足a[x] * k < a[y],且可以构造出的数(即a[x]+a[y])的最大值。
假设a的前i项已经求出,由于前i项最大已经可以构造出b[i],那么b[i]+1就无法被构造出来,所以需要另外开一项a[i+1] = b[i]+1。这时我们要求b[i+1]由于b[i+1]表示的是前i+1个a可以构造出来的最大的数所以一定得用到a[i+1],同时又要满足必须存在一项a[x]使得a[x]*k<a[i+1],所以我们就从之前的a中找出这个最大的a[x],那么b[i+1]=a[x]+a[i+1]。但是有可能之前数据太少,找不到a[x] * k < a[i+1];那也就是相当于a[i+1]无法构造出来,因此b[i+1] = a[i+1](例如i=0,a[x]只能取a[0],而a[0]*k>=a[1],那么b[1]只能等于a[1])。 提炼出来就是:
if(a[x]*k<a[i+1])
b[i+1] = a[x] + a[i+1];
else
b[i+1] = a[i+1];
然后就是要解决第一步取得最少且获胜的数量,那么先从n里减去小于n的最大的a[],然后又递归下去求这个剩下的n里最大的a[],找到n==a[]的a[]。也就是说这是这一串和里面最小的一个a了,将他输出就行了
定理1:对任意一个不可以写为2^k(k>=1)的数n,从它的二进制表达式中先取走最后一个1(即拿走m_A = (1<<k1)),得到一个数n1,那么再从n1中取走m_B(m_B<=m_A)个,得到n2。那么n2的二进制中最后一位1(第k2位)所在的位置所表示的数一定小于等于m_B((1<<k2) <= m_B)。
证明:我们可以把m_B写为二进制形式,而它的二进制中所有的1所在的位置我们记为a1,a2,a3....ak(k>=1)(a1<a2<a3<...<ak),也就是说m_B = (1<<a1)+(1<<a2)+...+(1<<ak)。那我们用n1 - m_B得到n2,由于在n1中a1位置是0,a1以下的所有位置都是0,而m_B中a1位置是1,m_B在a1以下位置也都是0,所以相减后得到的n2在a1位置一定是1。用二进制表示就是:
n 100...100...100000... 拿走最后一个1(m_A = (1<<k1)),得到
n1 100...100...000000... 再随便找一个m_B<=m_A
m_B 000...000...01010... 加粗部分从左至右为ak,ak-1...a2,a1,然后用n1 - m_B得到
n2 100...011...101010... n2在m_B最后一个1的位置(蓝色位置)也必定为1
定理2:任何一个非斐波拉契数都可以写为若干个不相邻的菲波拉契数的和,任何一个菲波拉契数都不能写为两个非相邻的斐波拉契数的和(原因很明显,因为Fn = Fn-1 + Fn-2,Fn-1与Fn-1相邻)
上面的思想过程转自神牛http://hi.baidu.com/lccycc_acm/item/a6f0dd0ec5c44a39f3eafcd3
有了上面的思想,代码实现就很简单了
#include <stdio.h> int a[],b[];
int main()
{
int n,k;
int T = ,Case = ;
while(~scanf("%d",&T))while(T--)
{
scanf("%d%d",&n,&k);
a[] = b[] = ;
int i=,j=;
while(n > a[i])
{
i++;
a[i] = b[i-] + ;
while(a[j+] * k < a[i])
{
j++;
}
if(k * a[j] < a[i])
{
b[i] = b[j] + a[i];
}
else b[i] = a[i];
}
printf("Case %d: ",Case++);
if(n == a[i])printf("lose\n");
else
{
int ans ;
while(n)
{
if(n >= a[i])
{
n -= a[i];
ans = a[i];
}
i --;
}
printf("%d\n",ans);
} }
return ;
}
POJ 3922A Simple Stone Game的更多相关文章
- POJ 3922 A simple stone game
题目: E - A simple stone game Time Limit:1000MS Memory Limit:65536KB 64bit IO Format:%I64d &am ...
- Something about 博弈(POJ 3922 A simple stone game)
先是题目,本来是第三次训练的题,在这特别提出来讲. 先是题目: E - A simple stone game Time Limit:1000MS Memory Limit:65536KB ...
- HDUOJ--------A simple stone game(尼姆博弈扩展)(2008北京现场赛A题)
A simple stone game ...
- HDU6237-A Simple Stone Game-找素因子(欧拉函数)-2017中国大学生程序设计竞赛-哈尔滨站-重现赛
A Simple Stone Game Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Ot ...
- 2017中国大学生程序设计竞赛-哈尔滨站 H - A Simple Stone Game
A Simple Stone Game Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Ot ...
- HDU 6237.A Simple Stone Game-欧拉函数找素因子 (2017中国大学生程序设计竞赛-哈尔滨站-重现赛)
A Simple Stone Game Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Ot ...
- uva 1567 - A simple stone game(K倍动态减法游戏)
option=com_onlinejudge&Itemid=8&page=show_problem&problem=4342">题目链接:uva 1567 - ...
- hdu 2486/2580 / poj 3922 A simple stone game 博弈论
思路: 这就是K倍动态减法游戏,可以参考曹钦翔从“k倍动态减法游戏”出发探究一类组合游戏问题的论文. 首先k=1的时候,必败态是2^i,因为我们把数二进制分解后,拿掉最后一个1,那么会导致对方永远也取 ...
- Poj 3468-A Simple Problem with Integers 线段树,树状数组
题目:http://poj.org/problem?id=3468 A Simple Problem with Integers Time Limit: 5000MS Memory Limit ...
随机推荐
- 1741. Communication Fiend(dp)
刷个简单的DP缓缓心情 1A #include <iostream> #include<cstdio> #include<cstring> #include< ...
- 1137. Bus Routes(dfs)
1137 做过一样的 怎么又忘了 再一次搜超时 不用回溯 #include <iostream> #include<cstdio> #include<cstring> ...
- 使用DX绘制3D物体时新手常犯错误,看不见物体时可以一一排查
1.镜头不对: 物体不在镜头范围内,检查视图矩阵,世界矩阵,投影矩阵. 2.颜色全黑: 打开光照情况下,MATERIAL全为0, 或,在没有打开光照情况下,颜色值为0,造成全黑.检查当前Materia ...
- POJ2135 最小费用最大流模板题
练练最小费用最大流 此外此题也是一经典图论题 题意:找出两条从s到t的不同的路径,距离最短. 要注意:这里是无向边,要变成两条有向边 #include <cstdio> #include ...
- Qt之运行一个实例进程
简述 发布程序的时候,我们往往会遇到这种情况: 只需要用户运行一个实例进程 用户可以同时运行多个实例进程 一个实例进程的软件有很多,例如:360.酷狗- 多个实例进程的软件也很多,例如:Visual ...
- PHPnow 升级后 PHP不支持GD、MySQL
来自http://tunps.com/php-unsupport-gd-and-mysql-after-upgrade-phpnow 最近磁盘格式化误操作后,最近两天都在忙于数据恢复,现在才恢复正常. ...
- [转]使用微软的官方类库CHSPinYinConv获得汉字拼音
原文链接:http://outofmemory.cn/code-snippet/4392/ms-CHSPinYinConv-convert-hanzi-to-pinyin 微软为中文,日文以及韩文提供 ...
- HDU 5303 Delicious Apples 美味苹果 (DP)
题意: 给一个长为L的环,起点在12点钟位置,其他位置上有一些苹果,每次带着一个能装k个苹果的篮子从起点出发去摘苹果,要将全部苹果运到起点需要走多少米? 思路: 无论哪处地方,只要苹果数超过k个,那么 ...
- 【解决方案】jquery live的change事件在IE下失效
$("#spanChildSec select").live("change", function () { //处理内容 ...
- java/python中获取当前系统时间,并与字符串相互转换格式,或者转化成秒数,天数等整数
java转换成秒数 Date类有一个getTime()可以换回秒数,例如: public class DateToSecond { public static void main(String[] a ...