题目链接 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. bzoj1063

    仔细观察可以发现,这个规划路径很像树链剖分 树链剖分的经典定理:任意一个点到根的所经过轻边不超过logn 而这个规划路径所走公路相当于轻边,也就是说,不便利度不会很大 那么直接dp即可,设f[x,i, ...

  2. Spring MVC 的请求参数获取的几种方法

    通过@PathVariabl注解获取路径中传递参数 @RequestMapping(value = "/{id}/{str}") public ModelAndView hello ...

  3. HNOI2004宠物收养所(平衡树)

    treap! var i,n,x,y,ans,a,b,root,tot,ft:longint; l,r,s,v,hr:..] of longint; procedure r_rotate(var x: ...

  4. kindeditor编辑器图片水印

    //upload_pic.ashx源码 <%@ webhandler Language="C#" class="edit_html_upload_pic" ...

  5. jfinal框架教程-学习笔记(一)

    JFinal  是基于 Java  语言的极速  WEB  + ORM  开发框架,其核心设计目标是开发迅速.代码量少.学习简单.功能强大.轻量级.易扩展.Restful.在拥有Java 语言所有优势 ...

  6. DbgPrint输出格式 Unicodestring

    DbgPrint输出格式 Unicodestring  1) 直接打印字符串. DbgPrint("Hello World!"); 2) 空结尾的字符串,你可以用普通得C语法表示字 ...

  7. 《C++ Primer 4th》读书笔记 第7章-函数

    原创文章,转载请注明出处:http://www.cnblogs.com/DayByDay/p/3912413.html

  8. js一些平时会用到的

    如何屏蔽页面js错误    <script language="javascript">    function killErrors()    {        re ...

  9. Redis Sentinel机制与用法

    概述 Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案,当用Redis做Master-slave的高可用方案时,假如master宕机了,Redis本身(包括它的很多客户端)都 ...

  10. C++ STL算法系列3---求和:accumulate

    该算法在numeric头文件中定义. 假设vec是一个int型的vector对象,下面的代码: //sum the elements in vec starting the summation wit ...