#博弈论,SG函数#洛谷 4077 [SDOI2016] 硬币游戏

题目传送门


分析

首先,不同的 \(c\) 是独立且等价的,设计 SG 函数,\(SG(MAXQ,a,b)\)

枚举 \(p,q\) 求出后继状态的 SG 值求 MEX 即可,要注意后继状态的 SG 值是 SG 函数的异或和(比如 \(SG(MAXQ,a,b-q)\text{ xor }SG(MAXQ,a,b-2q)\))。


代码

#include <iostream>
#include <string>
using namespace std;
const int N=30001,M=21;
int two[N],three[N],sg[M][M][M],Test,n,m,ans;
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	for (int i=1;i<N;++i){
		if (i%2==0) two[i]=two[i>>1]+1;
		if (i%3==0) three[i]=three[i/3]+1;
	}
	for (int o=1;o<M;++o)
	for (int i=0,I=1;I<N;I<<=1,++i)
	for (int j=0,J=1;J*I<N;J*=3,++j){
		int ans=0;
		for (int p=1;p<=i;++p){
			int now=0;
			for (int q=1;p*q<=i&&q<=o;++q)
			    now^=sg[o][i-p*q][j],ans|=1<<now;
		}
		for (int p=1;p<=j;++p){
			int now=0;
			for (int q=1;p*q<=j&&q<=o;++q)
			    now^=sg[o][i][j-p*q],ans|=1<<now;
		}
		sg[o][i][j]=__builtin_ctz(~ans);
	}
	for (cin>>Test;Test;--Test){
		cin>>n>>m,ans=0;
		for (int i=1,x;i<=n;++i){
			cin>>x;
			if (!x) ans^=sg[m][two[i]][three[i]];
		}
		if (ans) cout<<"win\n";
		    else cout<<"lose\n";
	}
	return 0;
}
posted @ 2025-06-29 10:48  lemondinosaur  阅读(12)  评论(0)    收藏  举报