问题描述:
分析:题目大意是两名球员轮流从N个球中挑出不多于M个射门,每个球半径都是R,离球门S。每次只能踢出L以内的距离。进最后一个球者胜,求谁有必胜策略?我们发现对数据进行处理之后,题目等价于给出n堆石子,每堆石子中每次最多取k个石子,每次最多选取m个石子堆做操作的博弈问题,首先我们将每堆石子堆对k+1取模简化运算,取一堆石子上的石子的做法我们是对所有的石子堆的sg值进行xor运算得到sg值,xor又称为半加运算,只进行加法而不进位,对于选取m堆石子的博弈我们的xor则是对于m+1进制下的半加运算,所以我们按位计算这个sg值,模拟m+1进制下的半加运算即可得到答案。
输入:
输入由几个案例组成,每个案例包含两行。
对于每个测试用例,第一行包含 4 个整数 N、M、L 和 R(1 <= M <= N <= 30, 0 < L < 100000000, 0 < R < 10000),用一个空格分隔。N是足球的数量,M是一名球员一回合可以射出的最大足球数,L是一名球员可以射出的最大距离,R是足球的半径。
下一行包含 N 个数字,S(1), S(2), ..., S(N) (0 < S(i) < 100000000),它们描述了足球和球门之间的距离。
输出:
对于每种情况,输出都包含一行描述获胜者的姓名。
样本输入:
样本输出:
程序代码:
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int N=30;
const double PI=acos(-1.0);
int n,m,l,r,a[N],sg[N];
int dis(int s) //看能否进球
{
return (int)(s/(2*PI*r))+1;
}
bool solve(){ //博弈函数
memset(sg,0,sizeof(sg));
int k=dis(l);
for(int i=0;i<n;i++)
for(int j=0,g=dis(a[i])%k;sg[j]+=g&1,g;j++,g>>=1);
for(int i=0;i<30;i++)
if(sg[i]%(m+1))
return 1;
return 0;
}
int main(){
while(~scanf("%d%d%d%d",&n,&m,&l,&r)){
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
puts(solve()?"Alice":"Bob");
}
return 0;
}
yjg