版权声明:本文为博主原创文章,你们可以随便转载 https://blog.csdn.net/Jaihk662/article/details/82933063
G. Stones
题目描述
有n堆石子,第i堆石子有xi个。
修修和栋栋轮流取石子,每人每次需要从任意一堆石子中取走个,修修先手。无法操作的人失败。此外,如果一个人取完了一堆石子,他会立即获胜。
不巧的是,修修除了数数以外啥都不会,他希望你帮他求出他能否获胜。
输入描述:
第一行一个整数t表示数据组数 (1 ≤ t ≤ 1000)。 每组数据第一行三个整数n,a,b (1 ≤ n ≤ 1000,1≤ a ≤ b ≤ 109),第二行n个整数 (1 ≤ xi ≤ 109)。
输出描述:
每组数据输出一行一个字符串:如果修修可以获胜输出Yes,否则输出No
输入
2 1 1 3 4 1 1 3 6
输出
No Yes
其实就是简单的Nim博弈,求出每一堆石子的SG(),然后异或起来就好了
不过这题多了一个条件:每个人都可以取[a, b]个,但若一个人取完了一堆石子,他会立即获胜
那么就相当于多了三种情况:
- 如果一开始某堆石子的范围就在[a, b]内,很显然先手直接获胜
- 如果某堆石子的范围是[0, a),那么这堆和没有一样
- 如果某堆石子个数大于b个,那么在求SG时,所有≤b的状态都不可达,因为到达就必输
然后就是常规操作了
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
#include<math.h>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
#define LL long long
#define mod 1000000007
int L, R;
int SG(int x)
{
if(x<=R)
return 0;
if(L==1)
return x%(L+R);
x -= R;
x %= (L+R);
x /= L;
if(x<=1)
x ^= 1;
return x;
}
int main(void)
{
int T, n, i, x, ans, p;
scanf("%d", &T);
while(T--)
{
ans = p = 0;
scanf("%d%d%d", &n, &L, &R);
for(i=1;i<=n;i++)
{
scanf("%d", &x);
if(x>=L && x<=R)
p = 1;
ans ^= SG(x);
}
if(p==1 || ans)
printf("Yes\n");
else
printf("No\n");
}
}
/*int cnt, a, b, tak[1005], Hash[1005], sg[1005];
void Getsg(int n)
{
int i, j;
memset(sg, 0, sizeof(sg));
for(i=1;i<=n;i++)
{
if(i>=a && i<=b)
continue;
memset(Hash, 0, sizeof(Hash));
for(j=1;tak[j]<=i&&j<=cnt;j++)
{
if(i-tak[j]>=a && i-tak[j]<=b)
continue;
Hash[sg[i-tak[j]]] = 1;
}
for(j=0;j<=n;j++)
{
if(Hash[j]==0)
{
sg[i] = j;
break;
}
}
}
}
int main(void)
{
int i;
while(scanf("%d%d", &a, &b)!=EOF)
{
cnt = 0;
memset(tak, 0, sizeof(tak));
for(i=a;i<=b;i++)
tak[++cnt] = i;
Getsg(30);
for(i=1;i<=30;i++)
printf("%d ", sg[i]);
puts("");
}
return 0;
}
*/