P1247 取火柴游戏

题目描述

输入k及k个整数n1,n2,…,nk,表示有k堆火柴棒,第i堆火柴棒的根数为ni;接着便是你和计算机取火柴棒的对弈游戏。取的规则如下:每次可以从一堆中取走若干根火柴,也可以一堆全部取走,但不允许跨堆取,也不允许不取。

谁取走最后一根火柴为胜利者。

例如:k=2,n1=n2=2,A代表你,P代表计算机,若决定A先取:

A:(2,2)→(1,2) {从一堆中取一根}

P:(1,2)→(1,1) {从另一堆中取一根}

A:(1,1)→(1,0)

P:(1,0)→ (0,0) {P胜利}

如果决定A后取:

P:(2,2)→(2,0)

A:(2,0)→ 0,0) {A胜利}

又如k=3,n1=1,n2=2,n3=3,A决定后取:

P:(1,2,3)→(0,2,3)

A:(0,2,3)→(0,2,2)

A已将游戏归结为(2,2)的情况,不管P如何取A都必胜。

编一个程序,在给出初始状态之后,判断是先取必胜还是先取必败,如果是先取必胜,请输出第一次该如何取。如果是先取必败,则输出“lose”。

输入格式

第一行,一个正整数k

第二行,k个整数n1,n2,…,nk

输出格式

如果是先取必胜,请在第一行输出两个整数a,b,表示第一次从第b堆取出a个。第二行为第一次取火柴后的状态。如果有多种答案,则输出<b,a>字典序最小的答案(即b最小的前提下a最小)。

如果是先取必败,则输出“lose”。

输入输出样例

输入 #1

3
3 6 9

输出 #1

4 3
3 6 5

输入 #2

4
15 22 19 10

输出 #2

lose

说明/提示

k<=500000

ni<=1e9

思路

Nim的模板题

变形处:输出第一个必胜的情况即可结束(字典序一定最小)

代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int N=500010;

int ans;
int a[N];
int n,sum;

int main () {
	scanf("%d",&n);
	for(int i=1; i<=n; i++) {
		scanf("%d",&a[i]);
		sum^=a[i];
	}
	if(!sum) {
		printf("lose\n");
		return 0;
	}
	for(int i=1; i<=n; i++)
		if((a[i]^sum)<a[i]) {
			printf("%d %d\n",a[i]-(a[i]^sum),i);
			for(int j=1; j<=n; j++)
				if(j!=i)
					printf("%d ",a[j]);
				else
					printf("%d ",sum^a[i]);
			return 0;
		}
	return 0;
}

原文地址:https://www.cnblogs.com/mysh/p/11333486.html

时间: 2024-10-12 08:26:08

P1247 取火柴游戏的相关文章

P1247 取火柴游戏 (奇异局势)

题目链接 题目描述 输入k及k个整数n1,n2,…,nk,表示有k堆火柴棒,第i堆火柴棒的根数为ni:接着便是你和计算机取火柴棒的对弈游戏.取的规则如下:每次可以从一堆中取走若干根火柴,也可以一堆全部取走,但不允许跨堆取,也不允许不取. 谁取走最后一根火柴为胜利者. 编一个程序,在给出初始状态之后,判断是先取必胜还是先取必败,如果是先取必胜,请输出第一次该如何取.如果是先取必败,则输出“lose”. 输入格式 第一行,一个正整数k 第二行,k个整数n1,n2,…,nk 输出格式 如果是先取必胜,

洛谷P1247 取火柴游戏 数学题 博弈论

这题就是NIM取石子游戏,但是NIM取石子方案并不是单一的,而是有多种方案的,现在让我们求字典序最小的方案,其实还是简单的,作为先手,如果是必胜局面,那我们肯定第一步把所有子异或和变为零 ,这样对于对方,这就是一个必败局面了 2.那我们来考虑怎么把局面变成必败局面呢,换句话说,怎么判断这一堆取不取呢, 假设a[ i ]不取他们的异或值为 y ,那么如果我们把a[ i ]变成 y 那么 y^y=0 就必胜了那就只要判断 if a[ i ]>=y 就可知在这一位上改变可不可行了,要字典序最小那就i从

P1247 取火柴游戏(异或理论)

https://www.luogu.com.cn/problem/P1247 #include <bits/stdc++.h> using namespace std; #define int long long const int maxn = 5e5 + 5; int n; int a[maxn]; signed main(){ //freopen("in","r",stdin); ios::sync_with_stdio(0); cin >&

【贪心】取火柴游戏

[贪心]取火柴游戏 题目描述 输入k及k个整数n1,n2,…,nk,表示有k堆火柴棒,第i堆火柴棒的根数为ni:接着便是你和计算机取火柴棒的对弈游戏.取的规则如下:每次可以从一堆中取走若干根火柴,也可以一堆全部取走,但不允许跨堆取,也不允许不取. 谁取走最后一根火柴为胜利者. 例如:k=2,n1=n2=2,A代表你,P代表计算机,若决定A先取: A:(2,2)→(1,2)    {从一堆中取一根} P:(1,2)→(1,1)    {从另一堆中取一根} A:(1,1)→(1,0) P:(1,0)

【博弈论】取火柴游戏

取火柴游戏 时间限制: 1 Sec  内存限制: 128 MB 题目描述 输入k及k个整数n1,n2,…,nk,表示有k堆火柴棒,第i堆火柴棒的根数为ni:接着便是你和计算机取火柴棒的对弈游戏.取的规则如下:每次可以从一堆中取走若干根火柴,也可以一堆全部取走,但不允许跨堆取,也不允许不取. 谁取走最后一根火柴为胜利者. 例如:k=2,n1=n2=2,A代表你,P代表计算机,若决定A先取: A:(2,2)→(1,2)    {从一堆中取一根} P:(1,2)→(1,1)    {从另一堆中取一根}

取火柴-博弈论

取火柴 (10分)C时间限制:3000 毫秒 | C内存限制:3000 Kb题目内容: 有n个火柴棍,两个游戏玩家a和b轮流取,规则是第一次取的人最少取1根,最多取n-1根,随后每人最多只能取对方上一次取的数目 的2倍,最少取1根.谁取到最后一根为胜者.试问先取的人是赢还是输. 输入描述n输出描述1表示胜,0表示输输入样例3输出样例0 解析:说白了,就是每个人只能取1或者2.(双方都不想因为自己而让对方的选择余地变大) #include<iostream> using namespace st

[数学故事]火柴游戏

一个最普通的火柴游戏就是两人一起玩,先置若干支火柴於桌上,两人轮流取,每次所取的数目可先作一些限制,规定取走最后一根火柴者获胜. 规则一:若限制每次所取的火柴数目最少一根,最多三根,则如何玩才可致胜? 例如:桌面上有 n=15 根火柴,甲.乙两人轮流取,甲先取,则甲应如何取才能致胜? 为了要取得最后一根,甲必须最后留下零根火柴给乙,故在最后一步之前的轮取中,甲不能留下1根或2根或3根,否则乙就可以全部取走而获胜.如果留下4根,则乙不能全取,则不管乙取几根(1或2或3),甲必能取得所有剩下的火柴而

BZOJ 1978: [BeiJing2010]取数游戏 game( dp )

dp(x)表示前x个的最大值,  Max(x)表示含有因数x的dp最大值. 然后对第x个数a[x], 分解质因数然后dp(x) = max{Max(t)} + 1, t是x的因数且t>=L ----------------------------------------------------------------------------------------- #include<cstdio> #include<cmath> #include<cstring>

poj 1067||hdu 1527 取石子游戏(博弈论,Wythoff Game)

取石子游戏 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 37893   Accepted: 12684 Description 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子:二是可以在两堆中同时取走相同数量的石子.最后把石子全部取完者为胜者.现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者