AcWing 891
891. Nim游戏
给定 nn 堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。
输入格式
第一行包含整数 nn。
第二行包含 nn 个数字,其中第 ii 个数字表示第 ii 堆石子的数量。
输出格式
如果先手方必胜,则输出 Yes
。
否则,输出 No
。
数据范围
1≤n≤1051≤n≤105,
1≤每堆石子数≤1091≤每堆石子数≤109
输入样例:
2
2 3
输出样例:
Yes
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5;
long long a[N];
int main()
{
int n;
cin>>n;
for (int i = 0; i < n; i ++ )
cin>>a[i];
int sky=0;
for (int i = 0; i < n; i ++ )
sky^=a[i];
if(sky==0)
cout<<"No"<<endl;
else
cout<<"Yes"<<endl;
}
892. 台阶-Nim游戏
现在,有一个 nn 级台阶的楼梯,每级台阶上都有若干个石子,其中第 ii 级台阶上有 aiai 个石子(i≥1i≥1)。
两位玩家轮流操作,每次操作可以从任意一级台阶上拿若干个石子放到下一级台阶中(不能不拿)。
已经拿到地面上的石子不能再拿,最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。
输入格式
第一行包含整数 nn。
第二行包含 nn 个整数,其中第 ii 个整数表示第 ii 级台阶上的石子数 aiai。
输出格式
如果先手方必胜,则输出 Yes
。
否则,输出 No
。
数据范围
1≤n≤1051≤n≤105,
1≤ai≤1091≤ai≤109
输入样例:
3
2 1 3
输出样例:
Yes
只考虑奇数台阶
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
signed main()
{
int a=0;
int n;
cin >> n;
for (int i = 1; i <= n; i ++ )
{
int k;
cin>>k;
if(i%2)
a^=k;
}
if(a)
cout << "Yes";
else
cout << "No";
}
AcWing 893. 集合-Nim游戏
给定 nn 堆石子以及一个由 kk 个不同正整数构成的数字集合 SS。
现在有两位玩家轮流操作,每次操作可以从任意一堆石子中拿取石子,每次拿取的石子数量必须包含于集合 SS,最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。
输入格式
第一行包含整数 kk,表示数字集合 SS 中数字的个数。
第二行包含 kk 个整数,其中第 ii 个整数表示数字集合 SS 中的第 ii 个数 sisi。
第三行包含整数 nn。
第四行包含 nn 个整数,其中第 ii 个整数表示第 ii 堆石子的数量 hihi。
输出格式
如果先手方必胜,则输出 Yes
。
否则,输出 No
。
数据范围
1≤n,k≤1001≤n,k≤100,
1≤si,hi≤100001≤si,hi≤10000
输入样例:
2
2 5
3
2 4 7
输出样例:
Yes
#include <cstring>
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
const int N = 110, M = 10010;
int n, m;
int s[N], f[M];
//s[N]存储可以每次拿取的石子数量
//f[N]存储x的SG值
int sg(int x)
{
if (f[x] != -1) return f[x];
set<int> S;
//SG(x) = mex(S),其中 S 是 x 后继状态的SG函数值的集合
//求S
//后继状态eg. x- {1,2}={x-2,x-1};
for (int i = 0; i < m; i ++ )
{
int sum = s[i];
if (x >= sum) S.insert(sg(x - sum));
}
//mex运算
for (int i = 0; ; i ++ )
if (!S.count(i))
return f[x] = i;
}
int main()
{
cin >> m;
for (int i = 0; i < m; i ++ ) cin >> s[i];
cin >> n;
memset(f, -1, sizeof f);
int res = 0;
for (int i = 0; i < n; i ++ )
{
int x;
cin >> x;
res ^= sg(x);
}
if (res) puts("Yes");
else puts("No");
return 0;
}