取(2堆)石子游戏
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 567 Accepted Submission(s): 348
Problem Description
有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。如果你胜,你第1次怎样取子?
Input
输入包含若干行,表示若干种石子的初始情况,其中每一行包含两个非负整数a和b,表示两堆石子的数目,a和b都不大于1,000,000,且a<=b。a=b=0退出。
Output
输出也有若干行,如果最后你是败者,则为0,反之,输出1,并输出使你胜的你第1次取石子后剩下的两堆石子的数量x,y,x<=y。如果在任意的一堆中取走石子能胜同时在两堆中同时取走相同数量的石子也能胜,先输出取走相同数量的石子的情况.
Sample Input
1 2
5 8
4 7
2 2
0 0
Sample Output
0
1
4 7
3 5
0
1
0 0
1 2
Author
Zhousc
Source
这道取石子的很有意思。YY的
思路:
{
首先是判断是否是奇异状态,当然这很简单。
是的话,输出0;
如果不是,先输出1,然后输出第一取而形成奇异状态的情况了。
问题当然也就在这。
到这我们就有两种策略了。
1.同时从两堆种取
2.从1堆中取。
先解决1:这个也简单,知道判断奇异状态,这个就很容易了。
通过k,可以求出aj,bj,这样就可以判断。
难点在2: 将其分类,如果输入的数字分别是 n,m
假如n是aj,------》那么求bj,判断bj是否满足 bj<=m; //(1)
假如n是bj, ------》 那么求aj,判断aj是否满足 aj<=n; //(2)
假如m是aj,------》那么求出bj,判断bj......... bj<=n; //不满足的。
假如m是bj,-------》那么求出aj,判断aj......... aj<=n; //(3)
由于aj<bj,所以我们可以知道,第三个假如不要求的,因为不可能满足.
讨论完了,如何求????
提供一种思路:由于 bk=ak+k; ak=(k*(1+sqrt(5.))/2.0);来求取各值。
但是,这样的话,会和奇异状态的特征(任何一个自然数,只存在一组奇异状态里)矛盾。
因为,对于n来说,只能存在(1)或者(2)中的一种,如果按这样的思路
就会更可能有2种了。
刚开始纠结住了。
另一种思路:打表。
暴力解决一切,用通过k来打表,这样就能避免第一张思路的问题了,然后用二分查找。
当然还要处理一个问题,(2) (3)的结果可能是相同的,需要判断一下,tmp的作用。
}
表示数据很水0ms过的。也可能存在错误,数据就过了。
#include<stdio.h> #include<math.h> int f[500003]={0},q[500003]={0}; void dabiao() { int k,aj,bj; double tmp; tmp=(1.0+sqrt(5.0))/2.0; for(k=1;k<=500000;k++) { aj=(int)(k*tmp); bj=aj+k; f[k]=aj; q[k]=bj; } } int EF(int l,int r,int num,int a[500003]) { int mid; mid=(l+r)/2; while(l<r) { if(a[mid]>num) r=mid-1; else if(a[mid]<num) l=mid+1; else return mid; mid=(l+r)/2; } return mid; } int main() { int k,n,m,t,aj,bj,tmp; dabiao(); while(scanf("%d%d",&n,&m)>0) { if(n==0&&m==0)break; k=m-n; t=(int) (k*(1.0+sqrt(5.0))/2.0); if(t==n) { printf("0\n"); continue; } printf("1\n"); aj=t; bj=t+k; if(aj<=n&&bj<=m) printf("%d %d\n",aj,bj); k=EF(1,500000,n,f); //n aj if(f[k]==n) { if(q[k]<=m) { printf("%d %d\n",f[k],q[k]); } } tmp=-1; k=EF(1,500000,n,q); // n bj if(q[k]==n) { if(f[k]<=m) { printf("%d %d\n",f[k],q[k]); tmp=q[k]-f[k]; } } k=EF(1,500000,m,q); // m bj if(q[k]==m) { if(f[k]<=n&&tmp==-1) printf("%d %d\n",f[k],q[k]); } } return 0; }