A simple stone game (poj3922,博弈)

41 篇文章 0 订阅
4 篇文章 0 订阅

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=27048#problem/G

http://poj.org/problem?id=3922

A simple stone game 

After he has learned how to play Nim game, Mike begins to try another stone game which seems much easier. 

The game goes like this: Two players start the game with a pile of n stones. They take stones from the pile in turn and every time they take at least one stone. The one who goes first can take at most n-1 stones for his first move. From then on a player can take at most k times as many stones as his opponent has taken last time. For example, if one player take m stones in his turn, then the other player can take at most k * m stones next time. The player who takes the last stone wins the game. Suppose that those two players always take the best moves and never make mistakes, your job is to find out who will definitely win the game.

Input

The first line contains a integer t, indicating that there are t test cases following.(t<=20). 

Each test case is a line consisting of two integer n and k.(2<=n<=108,1<=k<=105).

Output

For each test case, output one line starting with Case N: , N is the case number. And then, if the first player can ensure a winning, print the minimum number of stones he should take in his first turn. Otherwise, print "lose". Please note that there is a blank following the colon.

Sample Input

16 1 

11 1 

32 2 

34 2 

19 3

Sample Output

Case 1: lose

Case 2: 1

Case 3: 3

Case 4: lose

Case 5: 4

Hint

When k = 1, the first player will definitely lose if the initial amount of stones is in the set {2, 4, 8, 16, 32, ...}. Let's call this kind of set first-player-lose set

When k = 2, the first-player-lose set is {2, 3, 5, 8, 13, 21, 34, 57 ...} , which happens to be the Fibonacci sequence starting from 2.

Source

Beijing 2008

[Submit]   [Go Back]   [

解析:

题意:总共有n个石头,两个人轮流取石,每次取石头至少要取一个,且第一次取不能超过n,记前一次取得个数为m,后一次取的个数不超过k*m.谁取了最后一个石头,谁就胜,现问,第一个人取石头的人是否会胜出,若是输出其第一次可取的的最少石头数,否则输出lose

解析:

博弈题,首先有个奇异状态,构造必败态。

PS:其实对于博弈题还是很弱、。。。。。。。。。

具体思路见:

http://blog.csdn.net/acm_cxlove/article/details/7836544

这题的思考过程非常有意义。

k=1的时候 可知必败局面都是2^i  n分解成二进制,然后先手取掉最后一个1.然后对方必然无法去掉更高的1,而对方取完我方至少还能拿掉最后一个导致对方永远取不完。

k=2的时候,必败局面都是斐波那契数列。利用“先手去掉最后一个1,则后手必不能去掉更高阶的1导致取不完”的思想,斐波那契数列有一个非常好的性质就是:任意一个整数可以写成斐波那契数列中的不相邻的项的和,于是将n写成这种形式,先取走最后一个1,对方能取的数是这个数*2,小于高2位的1,所以取不完。

 

K的时候, 想办法构造数列,将n写成数列中一些项的和,使得这些被取到的项的相邻两个倍数差距>k 那么每次去掉最后一个还是符合上面的条件。设这个数列已经被构造了项,第 项为a[ i ],前 项可以完美对1..b[ i ] 编码使得每个编码的任意两项倍数>K 那么有

a[ i+1 ] = b[ i ] + 1;这是显然的 因为b[ i ] + 1没法构造出来,只能新建一项表示

然后计算b[ i+1] 既然要使用 a[ i+1 ] 那么下一项最多只能是某个 a[ t ] 使得 a[ t ] * K < a[ i+1 ] 于是

b[ i ] = b[ t ] + a[ i+1 ]

然后判断n是否在这个数列里面

如果在,那么先手必败。否则不停的减掉数列a中的项构造出n的分解,最后一位就是了。

以上转自神牛:http://hi.baidu.com/lccycc_acm/item/a6f0dd0ec5c44a39f3eafcd3

做一些解释:首先是a[i]=b[i-1]+1;   b[i-1]是由a[0]……a[i-1]组成的最大的数,那么b[i-1]+1不可能用a[0]……a[i-1]组成。

然后是:if(a[j]*k<a[i])

b[i]=b[j]+a[i]; else

b[i]=a[i];  

要求b[j],表示a[0]……a[i]组成,那么显然是要用到a[i]的,不然不就成了b[i-1],既然用了a[i],但是又要使相邻的倍数在K以上。则找到最大的j,使

a[j]*k<a[i]那么满足条件,便是a[0]……a[j]能组成的最大的数,加上a[i],那么后者表示当前项不能和之前项组合,那么最大的数就只能是本身

Accepted 15832K 188MS C++ 809B 2013-07-24 09:23:03

*/


#include<stdio.h>
#include<string.h>
#include <iostream>
using namespace std;
const int maxn=2000000+10;
int fail[maxn],mwin[maxn];
int main()
{int i,j,k,n,T;
 int ans,c=0;
scanf("%d",&T);
while(T--)
{  memset(fail,0,sizeof(fail));
memset(mwin,0,sizeof(mwin));
scanf("%d%d",&n,&k);
printf("Case %d: ",++c);
if(n<=k+1)
{
printf("lose\n");
continue;
}
int x=0,y=0;
fail[0]=mwin[0]=1;
while(fail[x]<n)//构建必败表
{
x++;
fail[x]=mwin[x-1]+1;
while(fail[y+1]*k<fail[x])
 y++;
 if(fail[y]*k<fail[x])
 mwin[x]=fail[x]+mwin[y];
 else
 mwin[x]=fail[x];
}
if(fail[x]==n)
 {
 	printf("lose\n");
 	continue;
 }
 while(n)
 {
 	if(n>=fail[x])
 	{
 	 ans=fail[x];
 	 n-=fail[x];
 	}
 	x--;
 }
 printf("%d\n",ans);
}
return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值