两个足够聪明的人玩轮流取石头的游戏,谁取到最后一个石头谁就赢了,他们一次只能取1个、3个、7个或8个石头,写一程序判断n个石头时先取的人是输还是赢。
输入格式:
一个整数n,其值不超过10000000。
输出格式:
如果先取的人赢,请以单独一行输出1,否则输出0。
输入样例:
这里是3组输入。
1
10
300
输出样例:
上面3组数据对应的输出分别如下:
1
1
0
首先举个例子,假如石头的总数为1,那么第一个取的人必然获胜。
然而到了总数为2的时候,第一个取的人只能拿一个,所以剩下的那一个就落在了第二个人手中,第二个人获胜。
石头总数为3,第一个人取石头可以选择取一个,剩下的两个中第二个人也只能拿一个,最后一个石头还是落在第一个人手中;或者第一个人可以直接选择拿取三个石头完结比赛。
石头总数为4,第一个人依然有两种选择,拿一个或者三个,但是这样无论第一个人第一次拿取几个石头,最后一个石头必然落在第二个人手中,即第二个人必胜。
石头总数为5,
第一个人第一次依然有两种选择,
第一种情况
如果第一个人第一次拿1个,剩下的4个石头第二个人有两种选择的机会,第二个人的第一次可以拿一个或者三个石头。如果第二个人拿一个,剩下的三个石头会被第一个人的第二次全部拿走,这样第一个人获胜;如果第二个人拿三个,剩下的一个也会被第一个人第二次拿走,获胜的依旧是第一个人。
第二种情况
如果第一个人第一次拿三个,剩下的两个石头第二个人只有一种选择就是拿一个,剩下的一个石头会被第一个人第二次拿走,第一个人获胜
所以石头总数为5的情况第一个拿的人必胜。
举例到了这里明眼人已经看出来些许端倪,我们是不是可以发现,当第一个人拿一个石头的时候剩下的4个石头交给了第二个人手中做选择,那么通过我们上面的例子在石头总数为4的时候是不是第二个取石头的人必赢?既然第二个取石头的人必赢(总数为4的时候),那么第一个人把剩下的4个石头交给第二个人,第二个人就成了第一个拿石头总数为4的人,而此时的第一个拿石头总数为5的人在石头总数为4面前成了第二个人,也就是说此时第一个取石头总数为5的人必胜。
同理依然是总数为5,如果我们的第一个人拿了三个石头,那么剩下的两个石头交给第二个人做选择,第二个人成了取石头总数为2的第一个人,而取总数为5的第一个人变成了取石头总数为2的第二个人。上面的例子中石头总数为2的人是不是第二个取的人必胜?所以,我们应该有大致的理解了。
说成大白话就是,第一个取石头的人总是想尽办法把自己必输的石头数留给第二个人,也就是说两个大聪明绞尽脑汁把自己必输的局面留给另一个人。
采用的思路就是从一个石头到n个石头去试,如果第i-1或者i-3或者i-7或者i-8中有一种情况或多种是第一个人输,那么第一个人就会拿取对应的1,3,7,8个石头,把自己必输的局面留给另一个人,让自己成为必输局面的第二个拿石头的人。(看不懂的话就是:石头总数为6的时候第一个拿的人必输,当石头总数为9的时候,9-3=6,所以第一个人第一次就会拿3个石头,把6个石头留给第二个人)
经过这一番解释,代码应该特别容易实现:
#include<bits/stdc++.h>
using namespace std;
long long int a[100000005];
int main(){
long long int n;
a[1]=1;
a[2]=0;
a[3]=1;
a[4]=0;
a[5]=1;
a[6]=0;
a[7]=1;
a[8]=1;
cin>>n;
if(n<=8)cout<<a[n];
else{
for(int i=9;i<=n;i++){
if(a[i-1]==0)a[i]=1;
else if((a[i-3]==0)||(a[i-7]==0)||(a[i-8]==0))a[i]=1;
else a[i]=0;
}
cout<<a[n];
}
return 0;
}
但是但是!
这个题肯定有内存的限制,题目上没说,如果是平常的64M的内存的话这样是可以过的,但是我记得这个题的内存要求是1M,所以这样做会超内存。不过我们可以利用这个代码实验大量的数据,找出其中的规律。
经过大量数据测试后得出规律:当n%15==0或2或4或6时都是第二个人赢,其余情况是第一个人赢了
这样的话就可以写出很简化的代码了:
AC代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
if(n%15==0)cout<<0;
else if(n%15==2)cout<<0;
else if(n%15==4)cout<<0;
else if(n%15==6)cout<<0;
else cout<<1;
}
看懂了点个赞支持下吧!