第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 10000) 第2 - T + 1行:每行2个数N,K。中间用空格分隔。(1 <= N,K <= 10^9)
共T行,如果A获胜输出A,如果B获胜输出B。
4 3 2 4 2 7 3 8 3
B A A B
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int main() { int n,k,t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&k); if(n%(k+1)) printf("A\n"); else printf("B\n"); } return 0; }
第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 10000) 第2 - T + 1行:每行1个数N。(1 <= N <= 10^9)
共T行,如果A获胜输出A,如果B获胜输出B。
3 2 3 4
B A A
const int maxn=45; bool vis[maxn]; int sg[maxn]; int a[5]={1,3,4}; void sgs() { for(int i=0;i<maxn;i++) { memset(vis,false,sizeof(vis)); for(int j=0;j<3;j++) { if(i>=a[j]) vis[sg[i-a[j]]]=true; } for(int j=0;;j++) { if(!vis[j]) { sg[i]=j; break; } } printf("%d %d\n",i,sg[i]); } }
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; int main() { int t; scanf("%d",&t); while(t--) { int n; scanf("%d",&n); if(n%7==0||n%7==2) printf("B\n"); else printf("A\n"); } return 0; }
第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 1000) 第2 - T + 1行:每行1个数N。(1 <= N <= 10^1000)
共T行,如果A获胜输出A,如果B获胜输出B。
3 2 3 4
A B A
const int maxn=1000+100; int sg[maxn]; bool vis[maxn]; int main() { for(int i=0;i<50;i++) { memset(vis,false,sizeof(vis)); for(int j=0;(1<<j)<=i;j++) { int s=i-(1<<j); vis[sg[s]]=true; } for(int j=0;;j++) { if(!vis[j]) { sg[i]=j; break; } } printf("%d ",sg[i]); } return 0; }
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; char s[maxn]; int main() { int t; scanf("%d",&t); while(t--) { scanf("%s",s); int n=strlen(s); int ans=0; for(int i=0;i<n;i++) { ans=ans+(s[i]-'0'); } if(ans%3) printf("A\n"); else printf("B\n"); } return 0; }
第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 1000) 第2 - T + 1行:每行1个数N。(1 <= N <= 10^9)
共T行,如果A获胜输出A,如果B获胜输出B。
3 2 3 4
B B A
这个游戏叫做Fibonacci Nim,肯定和Fibonacci数列:f[n]:1,2,3,5,8,13,21,34,55,89,… 有密切的关系。如果试验一番之后,可以猜测:先手胜当且仅当n不是Fibonacci数。换句话说,必败态构成Fibonacci数列。
这里需要借助“Zeckendorf定理”(齐肯多夫定理):任何正整数可以表示为若干个不连续的Fibonacci数之和。
先看看FIB数列的必败证明:
1、当i=2时,先手只能取1颗,显然必败,结论成立。
2、假设当i<=k时,结论成立。
则当i=k+1时,f[i] = f[k]+f[k-1]。
则我们可以把这一堆石子看成两堆,简称k堆和k-1堆。
(一定可以看成两堆,因为假如先手第一次取的石子数大于或等于f[k-1],则后手可以直接取完f[k],因为f[k] < 2*f[k-1])
对于k-1堆,由假设可知,不论先手怎样取,后手总能取到最后一颗。下面我们分析一下后手最后取的石子数x的情况。
如果先手第一次取的石子数y>=f[k-1]/3,则这小堆所剩的石子数小于2y,即后手可以直接取完,此时x=f[k-1]-y,则x<=2/3*f[k-1]。
我们来比较一下2/3*f[k-1]与1/2*f[k]的大小。即4*f[k-1]与3*f[k]的大小,由数学归纳法不难得出,后者大。
所以我们得到,x<1/2*f[k]。
即后手取完k-1堆后,先手不能一下取完k堆,所以游戏规则没有改变,则由假设可知,对于k堆,后手仍能取到最后一颗,所以后手必胜。
即i=k+1时,结论依然成立。
对于不是FIB数,首先进行分解。
分解的时候,要取尽量大的Fibonacci数。
比如分解85:85在55和89之间,于是可以写成85=55+30,然后继续分解30,30在21和34之间,所以可以写成30=21+9,
依此类推,最后分解成85=55+21+8+1。
则我们可以把n写成 n = f[a1]+f[a2]+……+f[ap]。(a1>a2>……>ap)
我们令先手先取完f[ap],即最小的这一堆。由于各个f之间不连续,则a(p-1) > ap + 1,则有f[a(p-1)] > 2*f[ap]。即后手只能取f[a(p-1)]这一堆,且不能一次取完。
此时后手相当于面临这个子游戏(只有f[a(p-1)]这一堆石子,且后手先取)的必败态,即先手一定可以取到这一堆的最后一颗石子。
同理可知,对于以后的每一堆,先手都可以取到这一堆的最后一颗石子,从而获得游戏的胜利。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int maxn=50; long long f[50]; int main() { f[1]=1,f[2]=2; for(int i=3;i<maxn;i++) f[i]=f[i-1]+f[i-2]; int t; scanf("%d",&t); while(t--) { int n; scanf("%d",&n); int sign=1; for(int i=1;i<maxn;i++) { if(f[i]>n) break; if(f[i]==n) { sign=0; break; } } if(sign) printf("A\n"); else printf("B\n"); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
51nod Bash游戏(V1,V2,V3,V4(斐波那契博弈))
原文地址:http://blog.csdn.net/caduca/article/details/47840643