http://acm.hdu.edu.cn/showproblem.php?pid=6266
题目大意:
H
a
k
a
s
e
Hakase
Hakase和
N
a
n
o
Nano
Nano轮流对
n
n
n堆石子进行操作,第
i
i
i堆石子有
a
i
a_i
ai个石子,每一次操作可以选取某一堆石子取走任意数量的石子(至少取走
1
1
1个),取走最后一个石子的人获胜,而
H
a
k
a
s
e
Hakase
Hakase开启了作弊模式,也就是说他每次要做两次操作,而
N
a
n
o
Nano
Nano只能做一次操作,现在问你
H
a
k
a
s
e
Hakase
Hakase能否获胜。
思路:首先考虑 H a k a s e Hakase Hakase先手的情况,考虑 n n n堆石子的个数均为 1 1 1的情况,很容易发现此时当且仅当 n % 3 = 0 n\%3=0 n%3=0的时候, H a k a s e Hakase Hakase才会失败,以此情况进行扩展,不难发现其余的任意情况 H a k a s e Hakase Hakase先手都是必胜的(考虑 H a k a s e Hakase Hakase可以消去 1 1 1堆或 2 2 2堆,总能找到必胜的情况);现在考虑 H a k a s e Hakase Hakase后手的情况,因为已经得到了先手必败态,只要 N a n o Nano Nano经过 1 1 1次操作能把当前状态转换为先手必败态,那么 H a k a s e Hakase Hakase后手就是必败的,那么当前状态仅有两种情况:(1) n % 3 = 0 n\%3=0 n%3=0,且仅有 1 1 1堆石子个数不为 1 1 1;(2) n % 3 = 1 n\%3=1 n%3=1,且至少有 n − 1 n-1 n−1堆石子的个数为 1 1 1。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<unordered_map>
#define pr pair<int,int>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
int a[maxn];
int n,t,d;
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&d);
int tot=0,u;
for(int i=0;i<n;i++)
{
scanf("%d",&u);
if(u==1)
++tot;
}
if(d==1)// Hakase 先手
{
if(tot==n&&n%3==0)
printf("No\n");
else
printf("Yes\n");
}
else // Hakase 后手
{
if((n%3==0&&tot==n-1)||(n%3==1&&tot>=n-1))
printf("No\n");
else
printf("Yes\n");
}
}
return 0;
}