题目链接 见文件第一题
题目描述
桌子上刚开始有 n 堆棋子,第 i 堆棋子有 ai (ai>0)个棋子。
两个年轻人轮流操作。每次操作,可以从当前剩余的所有棋子堆中,选择出
棋子数量最少的
(如果有多堆棋子满足条件,则在它们中任选一堆)某一堆棋子,然后从中拿走任意数量的棋子。
要求拿走的数量不能为
0
,不能超过这一堆所剩余的棋子数。
拿走桌子上最后一颗棋子的人获胜。
请问,在当前局面下,两个年轻人都采用最优策略,先手的人是否能够取胜?
输入格式
第一行,一个正整数 T,表示测试组数。
每组数据,第一行,一个整数 n。
接下来一行, n 个整数,ai 表示第 i 堆的棋子数。
输出格式
输出 T 行。
对每组数据,如果先手存在必胜策略,则输出
Yes
否则输出
No
样例
样例输入
2
2
1 1
1
3
样例输出
NoYes
提示
【样例
1
解释】
第一局,先手拿走第一堆的棋子,只能拿一颗。后手拿走第二堆的棋子,后手获得胜利。
第二句,先手拿走第一堆的全部棋子,先手获得胜利。
【数据范围】
对30%的数据满足,n ≤ 18,0<ai ≤ 10
对60%的数据满足,n ≤ 2000,0<ai ≤ 1000
对100%的数据满足,0 <T ≤ 10,n ≤ 10^4,0 < ai ≤ 10^18
时间限制 1.00s
内存限制
256.00MB
题解
其实这个题只要推出结论了就很简单了,首先我们可以明确如果只有一堆,那么先拿的人只需要全部拿走就可以获胜,所以只有一堆时,先手必胜。如果不只一堆,那么我们需要统计棋子数量为1的堆数,当所有的ai=1的棋子堆都被取完后,此时谁是先手则必胜,因为i<n时,我们只要每次将当前棋子堆取至只剩一个,到最后一堆时先手取完所有棋子获胜。如果所有堆的棋子数都是1,此时若为奇数堆,则先手必胜,反之,则先手必败。
实在不理解的可以看看代码。这个题很简单,但是我写的时候sum忘记每次归零了,差点爆零了(呜呜呜),写出来提醒自己下次不要忘记。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#define maxn 10010
using namespace std;
int n,t,sum;
long long a[maxn];
inline long long read(){
int f=1,k=0;
char c=getchar();
while(!isdigit(c)){
if(c=='-') f=-1;
c=getchar();
}
while(isdigit(c)){
k=k*10+(c-48);
c=getchar();
}
return f*k;
}
int main(){
scanf("%d",&t);
while(t--){
sum=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
a[i]=read();
if(a[i]==1) sum++;
}
if(n==1){
printf("Yes\n");
continue;
}
else{
if(sum==n){
if(sum%2==0){
printf("No\n");
continue;
}
else{
printf("Yes\n");
continue;
}
}
else if(sum==0){
printf("Yes\n");
continue;
}
else{
if(sum%2==0){
printf("Yes\n");
continue;
}
else{
printf("No\n");
continue;
}
}
}
}
return 0;
}