题目描述
简易版本
两个顶尖聪明的人在玩游戏,有n个石子,每人可以随便拿1~m个石子,不能拿的人为败者,问谁会胜利
- 如果n∈[1,m],先手必胜
- n == m+1,先手必败。推广可知 n==k(m+1)时先手必败
- n == k(m+1)+r,先手必胜。先手拿去r个,后手拿去x个,先手之后拿去 m+1-x个即可将局势转变为第二种情况,取胜。
简而言之就是面临 n % (m+1) == 0的人必败。
#include<cstdio>
int main()
{
int n,m;
scanf("%d%d",&n,&m);
if(n % (m+1) !=0) printf("first win");
else printf("second win");
return 0;
}
例题
POJ2368
有K(K∈[3,100 000 000 ])个石子,每次最多取L个,确定L(2 <= L < K)使得后手胜利。
那么我们就要让先手面临 K % (L+1) == 0的局势,找出K的因子中大于2的减一就是所求L。注意求因子的过程不能枚举,会TLE。
#include <iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int main(){
int sp[10010];
int n;
while(scanf("%d",&n) != EOF){
int ans = 1;
int size = 0;
for(int i = 1; i * i<= n;++i){
if(n % i == 0){
sp[size++] = i;
sp[size++] = n / i;
}
}
sort(sp,sp + size);
for(int i = 0;i < size;++i){
if(sp[i] > 2){
ans = sp[i];
break;
}
}
printf("%d\n",ans-1);
}
return 0;
}
升级版
有三个数字n,p,q,表示一堆硬币一共有n枚,从这个硬币堆里取硬币,一次最少取p枚,最多q枚,如果剩下少于p枚就要一次取完。两人轮流取,直到堆里的硬币取完,最后一次取硬币的算输。
分两种大情况:
- n % (p + q) == 0,先手必胜。先手取q个,后手取m个,先手之后取p+q-m个,最后留给后手的剩下p个,只能一次性全取光。
- n %(p+q) == s
s 范围 结果(胜利) 取胜步骤 剩余 备注 1<=s<=p 后手 先手取m个,后手取p+q-m个 留给先手s个 p<s<=q 先手 先手取t个,使得1<= s-t <=p,后手取m个,先手取p+q-m个 留给后手s-t个 即转换为情况2.1 q<s<=p+q 先手 先手取q个,余数s<p,后手取m,先手取p+q-m 留给后手m 即转换为情况2.1
以上可知,面临的局势的余数在1-p中的人必输。
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int n, p, q;
while(~scanf("%d%d%d",&n, &p, &q))
{
if(n % (p+q) <= p && n % (p+q) >= 1)
printf("LOST\n");
else
printf("WIN\n");
}
return 0;
}
``