bzoj 4035: [HAOI2015]T3 SG函数

本文介绍了一种针对大规模博弈论问题的优化解决方案。通过将问题转化为存在若干白点并将其全部翻转成黑点的游戏,利用SG函数进行状态压缩,并通过优化递推过程降低时间复杂度至O(N),实现高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       博弈论神题。。

       首先把问题转化为存在若干白点,然后将所有点翻转成黑点,先全部翻转的为胜。这和原题是等价的,因为如果某一步选一个黑点翻是必胜策略,那么下一步对手可以选择翻同一个点而使局面变回来,因此考虑双方都是采取最好的策略因此不会有一方翻黑点。

       那么就把每一个白点看成是一个子游戏,最后将SG函数全部异或起来即可,由SG定理可知有:

       SG(i)=mex{SG[i*1]^SG[i*2]^...^SG[i*k]},k=[2,N/i]。

       然而N为10^9,因此不能直接递推。注意到实际上某一个SG[i]函数的值只和N/i有关,因此有用的状态只有O(N^0.5)个,然后根据上面的式子递推即可。

       但是还要考虑有用状态的保存问题,注意到有N^0.5个状态的下标<=N^0.5,这部分直接保存即可;另有N^0.5个状态的下标>=N^0.5,但是N/下标<=N^0.5且各不相同,因此用N除之后再保存即可。

       时间复杂度O(N),不过常数较小,可以通过。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define N 100005
using namespace std;

int n,m,c[2][N],a[N]; bool bo[N];
int nxt(int x,int y){ return (x==y)?y+1:y/(y/(x+1)); }
void pfs(){
	int i,j,now,x,t,cnt;
	for (i=1; i<=n; i=nxt(i,n)){
		now=cnt=0;
		for (j=2; j<=i; j=nxt(j,i)){
			x=i/j; t=(x>m)?c[1][n/x]:c[0][x];
			a[++cnt]=now^t; bo[a[cnt]]=1;
			if ((i/x-i/(x+1))&1) now^=t;
		}
		now=1; while (bo[now]) now++;
		if (i>m) c[1][n/i]=now; else c[0][i]=now;
		for (j=1; j<=cnt; j++) bo[a[j]]=0;
	}
}
int main(){
	scanf("%d",&n); m=(int)sqrt(n); pfs();
	int cas,cnt; scanf("%d",&cas);
	while (cas--){
		scanf("%d",&cnt); int ans=0,x;
		while (cnt--){
			scanf("%d",&x); x=n/x;
			ans^=(x>m)?c[1][n/x]:c[0][x];
		}
		puts((ans)?"Yes":"No");
	}
}


by lych

2016.3.15

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值