CSP-S 模拟 19/11/09 学园祭的游戏(博弈论)(SG)(整除分块)

CSP-S 模拟 19/11/09 学园祭的游戏(博弈论)(SG)(整除分块)_第1张图片


第一次考场写博弈论,好激动
暴力求 s g sg sg 函数还是很好做的
s g ( x ) = m e x ( s g ( i ) ) ( x − x b i ≤ i < x ) sg(x)=mex(sg(i))(x-\frac{x}{b_i}\le i< x) sg(x)=mex(sg(i))(xbixi<x)
然后把表打出来过后发现
CSP-S 模拟 19/11/09 学园祭的游戏(博弈论)(SG)(整除分块)_第2张图片
s g ( x ) = s g ( x − x b i − 1 ) ( x % b i ! = 0 ) sg(x)=sg(x-\frac{x}{b_i}-1)(x\%b_i!=0) sg(x)=sg(xbix1)(x%bi!=0)
s g ( x ) = x b i ( b i ∣ x ) sg(x)=\frac{x}{b_i}(b_i|x) sg(x)=bix(bix)
证明的话考虑一下求 m e x mex mex 的过程就可以了
这样就可以拿 70 p t s 70pts 70pts
发现 b i b_i bi 大的时候跳的次数多但是 x b i \frac{x}{b_i} bix 的取值不多
b i b_i bi 小的时候跳得飞快
于是当 b i ≤ a i b_i\le \sqrt {a_i} biai 时,暴力跳,最多 a i \sqrt {a_i} ai
b i > a i b_i> \sqrt {a_i} bi>ai 时,找到 x b i \frac{x}{b_i} bix 相同的一段一起减掉即可


考场上慢慢想感觉对 s g sg sg 函数有了一些新的理解
首先一个常识是 s g ( x ) sg(x) sg(x) 为所有子状态的 m e x mex mex,还有就是 s g sg sg 为 0 那么必败
为什么呢?
因为一个 s g sg sg 为 0 的话那么它的所有子状态都不为 0
一个 s g sg sg 不为 0 只需要一个子状态为 0
这就对应了一个状态必败当且仅当它的所有子状态为必胜状态
一个必胜状态只要可以到一个必败状态它就必胜
而一个游戏的 s g sg sg 为所有子游戏的 s g sg sg 的异或和又是为什么呢?
又有一个常识是 s g sg sg 的异或和为 0 的话那么必败
考虑到如果异或和为 0 那么任意走一步都会使异或和不为 0
如果异或和不为 0 ,假设异或和是 x x x,最大位的 1 在第 k 位,
那么一定可以找到一个 a i a_i ai 使得 x x x a i a_i ai 的第 k k k 位为 1
然后把 a i a_i ai 变成 a i a_i ai 异或 x x x ,就可以到达一个异或和为 0 的局面
因为取的是最大的一位,那么 a i a_i ai 异或了 x x x 过后一定小于 a i a_i ai
而根据 s g sg sg 的取 m e x mex mex 一个状态一定能到达所有小于它的状态
之前学没有懂,打了个表玩了玩竟然就有感觉了!


#include
#define cs const
using namespace std;
int read(){
	int cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
	while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
	return cnt * f;
}
int T, n;
int sg(int a, int b){ 
	if(a % b == 0) return a / b;
	return sg(a - a / b - 1, b);
}
int SG(int a, int b){
	int sz = sqrt(a);
	if(a / b > sz) return sg(a, b);
	while(a % b){
		int t = a / b + 1, nxt = a / b * b;
		a -= (a - nxt) / t * t;
		if(a % b) a -= a / b + 1;
	} return a / b;
}
int main(){
	T = read();
	while(T--){
		n = read();
		int ans = 0;
		for(int i = 1; i <= n; i++){
			int a = read(), b = read();
			ans ^= SG(a, b);
		} if(ans) puts("Setsuna");
		else puts("Kazusa");
	} return 0;
}

你可能感兴趣的:(校内模拟,博弈论,FSY的好题汇总)