luogu2575 高手过招 sg函数

9 篇文章 0 订阅

Description


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

游戏规则是这样的:

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

10%的数据T≤1,n≤1
另外10%的数据m≤1
100%的数据T≤100,n≤1000,m≤20,1≤pj≤20
By:Mul2016

Solution


显然每一行都是独立的,我们考虑求出每一行的sg
由于一定是20列,因此可以状压然后dfs预处理sg的值。然后就做完了

我才发现以前写的求sg函数的方法好像都是错的。由于桶是全局共用的,因此我们需要先求出后继状态的sg再取mex(具体看代码

Code


#include <stdio.h>
#include <string.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))

const int N=1048578;

int rec[N],sg[N],n;

void get_sg(int x) {
	if (~sg[x]) return ;
	rep(i,0,19) if (x&(1<<i)) {
		rep(j,i+1,19) if (!(x&(1<<j))) {
			int y=x; y^=(1<<i); y^=(1<<j);
			get_sg(y);
			break;
		}
	}// 这里要分开来写,以前都是合起来的╮(╯▽╰)╭
	rep(i,0,19) if (x&(1<<i)) {
		rep(j,i+1,19) if (!(x&(1<<j))) {
			int y=x; y^=(1<<i); y^=(1<<j);
			rec[sg[y]]=x;
			break;
		}
	}
	for (sg[x]=0;rec[sg[x]]==x;) sg[x]++;
}

int main(void) {
	fill(sg,-1);
	rep(i,0,(1<<20)-1) get_sg(i);
	int T; for (scanf("%d",&T);T--;) {
		int n,sum=0; scanf("%d",&n);
		rep(i,1,n) {
			int m,p=0; scanf("%d",&m);
			rep(j,1,m) {
				int x; scanf("%d",&x);
				p|=1<<(x-1);
			}
			sum^=sg[p];
		}
		puts((!sum)?"NO":"YES");
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值