题目链接 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的更多相关文章

  1. POJ 3922 A simple stone game

    题目: E - A simple stone game Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d &am ...

  2. Something about 博弈(POJ 3922 A simple stone game)

    先是题目,本来是第三次训练的题,在这特别提出来讲. 先是题目: E - A simple stone game Time Limit:1000MS     Memory Limit:65536KB   ...

  3. HDUOJ--------A simple stone game(尼姆博弈扩展)(2008北京现场赛A题)

    A simple stone game                                                                                  ...

  4. HDU6237-A Simple Stone Game-找素因子(欧拉函数)-2017中国大学生程序设计竞赛-哈尔滨站-重现赛

    A Simple Stone Game Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Ot ...

  5. 2017中国大学生程序设计竞赛-哈尔滨站 H - A Simple Stone Game

    A Simple Stone Game Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Ot ...

  6. 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 ...

  7. uva 1567 - A simple stone game(K倍动态减法游戏)

    option=com_onlinejudge&Itemid=8&page=show_problem&problem=4342">题目链接:uva 1567 - ...

  8. hdu 2486/2580 / poj 3922 A simple stone game 博弈论

    思路: 这就是K倍动态减法游戏,可以参考曹钦翔从“k倍动态减法游戏”出发探究一类组合游戏问题的论文. 首先k=1的时候,必败态是2^i,因为我们把数二进制分解后,拿掉最后一个1,那么会导致对方永远也取 ...

  9. Poj 3468-A Simple Problem with Integers 线段树,树状数组

    题目:http://poj.org/problem?id=3468   A Simple Problem with Integers Time Limit: 5000MS   Memory Limit ...

随机推荐

  1. hdu 4864 Task (贪心 技巧)

    题目链接 一道很有技巧的贪心题目. 题意:有n个机器,m个任务.每个机器至多能完成一个任务.对于每个机器,有一个最大运行时间xi和等级yi, 对于每个任务,也有一个运行时间xj和等级yj.只有当xi& ...

  2. Android ContentProvider和Uri详解 (绝对全面)

        ContentProvider的基本概念 : 1.ContentProvider为存储和读取数据提供了统一的接口 2.使用ContentProvider,应用程序可以实现数据共享 3.andr ...

  3. SharePoint的安装配置

    安装环境 1. Window server 2008 r2(sp2) OS.2. MS SQL Server 2008 r2.3. Office2010.4. IIS7以上.5. 确认服务器已经加入域 ...

  4. UVa 580 (递推) Critical Mass

    题意: 有两种盒子分别装有铀(U)和铅(L),现在把n个盒子排成一列(两种盒子均足够多),而且要求至少有3个铀放在一起,问有多少种排放方法. 分析: n个盒子排成一列,共有2n中方案,设其中符合要求的 ...

  5. web交互方式

    轮询:客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接. 优点:后端程序编写比较容易. 缺点:请求中有大半是无用,浪费带宽和服务器资源. 实例:适于小型应用. 长轮询:客 ...

  6. android中的ellipsize设置(省略号的问题)

    textview中有个内容过长加省略号的属性,即ellipsize,可以较偷懒地解决这个问题,哈哈~ 用法如下: 在xml中 android:ellipsize = "end"   ...

  7. gradle command not found

    find / -name 'gradle*' .... /Applications/Android Studio.app/Contents/gradle/gradle-2.10/bin/gradle ...

  8. ionic安装拍照选照片插件

    1.安装插件,也可以用ionic plugin add .... phonegap local plugin add https://git-wip-us.apache.org/repos/asf/c ...

  9. objective-c里的方法指针IMP的用法

    SGPopSelectView.h @interface SGPopSelectView : UIView @property (nonatomic, assign) SEL selector; @p ...

  10. UVA 658 It's not a Bug, it's a Feature! (最短路,经典)

    题意:有n个bug,有m个补丁,每个补丁有一定的要求(比如某个bug必须存在,某个必须不存在,某些无所谓等等),打完出来后bug还可能变多了呢.但是打补丁是需要时间的,每个补丁耗时不同,那么问题来了: ...