石子博弈

链接:https://www.nowcoder.com/acm/contest/203/G
来源:牛客网

题目描述

有n堆石子,第i堆石子有xi个。
修修和栋栋轮流取石子,每人每次需要从任意一堆石子中取走个,修修先手。无法操作的人失败。此外,如果一个人取完了一堆石子,他会立即获胜。
不巧的是,修修除了数数以外啥都不会,他希望你帮他求出他能否获胜。

输入描述:

第一行一个整数t表示数据组数 (1 ≤ t ≤ 1000)。
每组数据第一行三个整数n,a,b (1 ≤ n ≤ 1000,1≤ a ≤ b ≤ 10
9
),第二行n个整数
 (1 ≤ x
i
 ≤ 10
9
)。

输出描述:

每组数据输出一行一个字符串:如果修修可以获胜输出Yes,否则输出No。
示例1

输入

复制
2
1 1 3
4
1 1 3
6

输出

复制
No
Yes

题意 : 有 n 堆石子,石子个数是给定的,每次可以取出的石子个数是 a - b, 当一次完全取完某一堆时即代表获胜。
思路分析 :
  基本就是3种情况,
  1 . 当石子个数 < a 时,此时 sg 值为 0
  2 . 当石子个数 >= a && <= b 时,此时直接取胜
  3 . 当石子个数 > b 时,打表计算此时的 sg 值,找规律,但是要注意的是此时的后继状态是不能到达 a-b 的,因为到达就必输
代码示例 :
#include <bits/stdc++.h>
using namespace std;
#define ll long long

ll n, a, b;

ll SG(ll x){
	if (x <= b) return 0;
	if (a == 1) return x%(1+b);
	
	x -= b;
	x %= (a+b);
	x = x/a;
	if (x <= 1) x ^= 1;
	return x;
}

int main () {
	ll t;
	ll x;
	
	cin >> t;
	while(t--){
		scanf("%lld%lld%lld", &n, &a, &b);
		ll ans = 0;
		ll sign = 0;
		
		for(ll i = 1; i <= n; i++){
			scanf("%lld", &x);
			if (x >= a && x <= b) sign = 1;
			ans ^= SG(x);		
		}		
		if (ans || sign) puts("Yes");
		else puts("No");
	}	
	return 0;
}
东北日出西边雨 道是无情却有情
原文地址:https://www.cnblogs.com/ccut-ry/p/9744999.html