luoguP3235 [HNOI2014]江南乐 数论分块 + 博弈论


感觉其实很水?

题目就是一个Multi SG游戏,只需要预处理出所有的(sg)值即可(O(Tn))计算

对于计算(sg[n])而言,显然我们可以枚举划分了(x)堆来查看后继状态

那么,有(n;mod;x)(left lfloor frac{n}{x} ight floor + 1)的堆以及(x - n;mod;x)(left lfloor frac{n}{x} ight floor)的堆

暴力转移就是(O(10^{10}))

显然上面可以数论分块,再讨论一下奇偶即可

复杂度(O(10^5 sqrt 10^5))


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define ri register int
#define rep(io, st, ed) for(ri io = st; io <= ed; io ++)
#define drep(io, ed, st) for(ri io = ed; io >= st; io --)

const int sid = 2e5 + 5;
	
int T, F, tim;
int sg[sid], mex[sid];
	
inline void init() {
	rep(i, F, 100000) {
		++ tim;
		for(ri ii = 2, jj; ii <= i; ii = jj + 1) {
			jj = i / (i / ii); 
			int p = i / ii, S = i - p * ii, S2 = ii - S, SG = 0;
			if(S & 1) SG ^= sg[p + 1];
			if(S2 & 1) SG ^= sg[p]; mex[SG] = tim;
			if(ii + 1 > jj) continue;
			S = i - p * (ii + 1); S2 = (ii + 1) - S; SG = 0;
			if(S & 1) SG ^= sg[p + 1];
			if(S2 & 1) SG ^= sg[p]; mex[SG] = tim;
		}
		rep(j, 0, 100000) if(mex[j] != tim) 
		{ sg[i] = j; break; }
	}
}
	
int main() {
	cin >> T >> F;
	init();
	while(T --) {
		int n, x, SG = 0;
		cin >> n;
		rep(i, 1, n) { cin >> x; SG ^= sg[x]; }
		printf("%d ", SG ? 1 : 0);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/reverymoon/p/10152706.html