【ybtoj 博弈论课堂过关】【luogu P1247】【luogu P2197】【模板】nim 游戏 & 取火柴游戏 &【例题1】取火柴游戏

【例题1】取火柴游戏 & [ZJOI2009] 取石子游戏 & 【模板】nim 游戏


Link

ybtoj 【博弈论课堂过关】【例题1】取火柴游戏
luogu P1247 取火柴游戏
luogu P2197 【模板】nim 游戏
题面//因为不知道侵不侵权所以就是题面是私密的,有账号的直接看转送门就可了


题目大意

有 n 个火柴堆,第 i 堆火柴堆有 a[i] 根火柴
你和人机轮流取火柴

  • 每次只能取一堆的火柴(不能跨堆取)
  • 每次必须取,可以全部取完

拿走最后一根火柴的一方赢


解题思路

来来来,各位先食用一些论证
结论为,这种NIM游戏,先手赢,当且仅当 A 1   x o r   A 2   x o r . . .   A n   =   a n s   ≠ 0 A_1\ xor\ A_2\ xor...\ A_n\ =\ ans\ ≠ 0 A1 xor A2 xor... An = ans =0

那么方案怎么算呢??
当先手赢时,一定存在一个 A a n s w   x o r   a n s   <   A a n s w A_{answ}\ xor\ ans\ <\ A_{answ} Aansw xor ans < Aansw
这个 A a n s w   x o r   a n s A_{answ}\ xor\ ans Aansw xor ans就是第一步取完,剩下的火柴
那么 A a n s w   −   ( A a n s w   x o r   a n s ) A_{answ}\ -\ (A_{answ}\ xor\ ans) Aansw  (Aansw xor ans)就是第一步取的火柴


Code

#include <iostream>
#include <cstdio>

using namespace std;

int n, a[501000], ans;

int main() {
	scanf("%d %d", &n, &a[1]);
	ans = a[1];
	for(int i = 2; i <= n; i ++) {
		scanf("%d", &a[i]);
		ans ^= a[i];
	}
	if(ans == 0) printf("Lose");
		else {
			for(int i = 1; i <= n; i ++)
				if((a[i] ^ ans) < a[i]) {
					printf("%d %d\n", a[i] - (a[i] ^ ans), i);
					for(int j = 1; j < i; j ++)
						printf("%d ", a[j]);
					printf("%d ", a[i] ^ ans);
					for(int j = i + 1; j <= n; j ++)
						printf("%d ", a[j]);
					break;
				}
		}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值