「小奇模拟赛」[BZOJ3576] 小奇的博弈2 sg函数

题目&题解:点击打开链接(此题好像不在bzoj上)

博弈的关键就是求sg。

此题为优化暴力求sg的过程。

有些题是找规律或利用性质求sg

当然也有个别题直接抓住性质不用求sg,如bzoj4975


求sg的关键:sg=mex{后继状态}

                    sg=xorsum{当前所有独立状态}

打表找规律常开脑洞

//调题时仔细改错,不要打错字符
#include<bits/stdc++.h>
using namespace std;
#define maxn 100020

int sg[maxn],vis[maxn],cnt[maxn];
int n,F,T,a[maxn],dfstime;

int getsg(int x){
	if ( x < F ) return sg[x] = 0;
	if ( sg[x] != -1 ) return sg[x];
	//用时间戳打标记,不用清空数组
	//一定要先递归再求当前sg,要不然cnt的标记会被覆盖
	for (register int i = 2,next ; i <= x ; i = next + 1){
		getsg(x / i + 1);
		getsg(x / i );
		next = x / (x / i);
	}
	++dfstime;
	for (register int i = 2,next ; i <= x ; i = next + 1){
		int a = x % i , b = i - a , cur = 0;
		next = x / (x / i);
		if ( a & 1 ) cur = sg[x / i + 1];
		if ( b & 1 ) cur ^= sg[x / i];
		cnt[cur] = dfstime;
		if ( next != i ){
			a = x % (i + 1) , b = i + 1 - a , cur = 0;
			if ( a & 1 ) cur = sg[x / i + 1];
			if ( b & 1 ) cur ^= sg[x / i];
			cnt[cur] = dfstime;
		}
	}
	sg[x] = 0;
	for (register int i = 0 ; cnt[i] == dfstime ; i++){
		sg[x]++;
	}
	return sg[x];
}
void init(){
	for (int i = 100000 ; i >= F ; i--) sg[i] = -1;
//	cout<<getsg(100)<<endl;
	//	for (int i = 100000 ; i >= 0 ; i--) sg[i] = getsg(i);
//cout<<getsg(100)<<endl;
		//	for (int i = 0 ; i <= 5 ; i++) cout<<sg[i]<<" ";
//	cout<<endl;	
}
int main(){
	freopen("input.txt","r",stdin);
//	freopen("1.out","w",stdout);
	scanf("%d %d",&T,&F);
	init();
	while ( T-- ){
		int ans = 0;
		scanf("%d",&n);
		for (int i = 1 ; i <= n ; i++) scanf("%d",&a[i]) , ans ^= getsg(a[i]);
		if ( ans ) cout<<1<<" ";
		else cout<<0<<" ";
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值