P2575 高手过招

Posted mysh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2575 高手过招相关的知识,希望对你有一定的参考价值。

题目描述

AKN玩游戏玩累了,于是他开始和同伴下棋了,玩的是跳棋!对手是wwx!这两位上古神遇在一起下棋,使得棋局变得玄幻莫测,高手过招,必有一赢,他们都将用最佳策略下棋,现在给你一个n*20的棋盘,以及棋盘上有若干个棋子,问谁赢?akn先手!

游戏规则是这样的:

对于一个棋子,能将它向右移动一格,如果右边有棋子,则向右跳到第一个空格,如果右边没有空格,则不能移动这个棋子,如果所有棋子都不能移动,那么将输掉这场比赛。

输入格式

第一行一个T,表示T组数据

每组数据第一行n,表示n*20的棋盘

接下来n行每行第一个数m表示第i行有m个棋子

随后跟着m个数pj表示第i行的棋子布局

输出格式

如果AKN能赢,则输出”YES”,否则输出”NO”

输入输出样例

输入 #1
2
1
2 19 20
2
1 19
1 18
输出 #1
NO
YES

说明/提示

10%的数据T≤1,n≤1

另外10%的数据m≤1

100%的数据T≤100,n≤1000,m≤20,1≤pj≤20

By:Mul2016

思路

考虑阶梯Nim,每次可以把一个石堆的任意个棋子移到下一级阶梯。

那么显然就是奇数层的SG异或起来

因为偶数层的操作后手可以做对称的操作

那么考虑这题,发现棋子间会互相影响,不好表示,所有自然而然的可以想到转换模型,发现空格的个数是不会变的,可以看作阶梯Nim。

代码:

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

const int N=50,M=1010;

int SG[N],f[M];
int n,t,ans,len;
int a[N],cnt[N];
int flag,top,tot;

int main () 
	scanf("%d",&t);
	while(t--) 
		ans=0;
		scanf("%d",&n);
		for(int i=1; i<=n; i++) 
			memset(cnt,0,sizeof(cnt));
			scanf("%d",&len);
			for(int j=1; j<=len; j++) 
				scanf("%d",&a[j]);
				cnt[a[j]]++;
			
			tot=0,top=20,flag=0;
			while(cnt[top])
				top--;
			for(; top; --top)
				if(!cnt[top]) 
					ans^=(flag?tot:0);
					flag^=1;
					tot=0;
				 else
					tot++;
			ans^=(flag?tot:0);
		
		if(ans)
			printf("YES\n");
		else
			printf("NO\n");
	
	return 0;

 

以上是关于P2575 高手过招的主要内容,如果未能解决你的问题,请参考以下文章

P2575 高手过招

洛谷 [P2575] 高手过招

高手过招 放“码”出击 | 2022 Google 全球编程比赛集结倒计时!

Luogu 2575 高手过招-SG函数

高手过招 放“码”出击 | 2022 Google 全球编程比赛集结倒计时!

LuoguP2575 高手过招(博弈论)