LG P3235 [HNOI2014]江南乐(SG函数)

题目
首先这个题SG函数很明显。
枚举分为多少堆然后对子状态的SG函数求mex就行。
但是直接枚举是 O ( n 2 ) O(n^2) O(n2)
可以用整除分块:
n个石子分成m堆:
n n n% m m m个大小为 ⌊ n m ⌋ + 1 \lfloor\frac nm\rfloor+1 mn+1的石堆。
m − n m-n mn% m m m个大小为 ⌊ n m ⌋ \lfloor\frac nm\rfloor mn的石堆。
现在只有 r = n r=n r=n% m m m m − r m-r mr的大小不确定了。
发现如果 u = ⌊ n m ⌋ u=\lfloor\frac nm\rfloor u=mn
m + + m++ m++ r − = u r-=u r=u, m − r − > m − r + u + 1 m-r->m-r+u+1 mr>mr+u+1
所以u为奇数时m-r奇偶不变,r奇偶变。
u为偶数时反之。

AC Code:

#include
#include
#include
#define maxn 100005
using namespace std;

int T,F,n;
int SG[maxn];
int vis[maxn],tim;

int ser(int x){
	if(SG[x]>=0) return SG[x];
	for(int i=2,nxt;i<=x;i=nxt+1){
		nxt=x/(x/i);
		int u = x / i;
		ser(u),ser(min(u+1,x-1));
	}
	++tim;
	for(int i=2,nxt;i<=x;i=nxt+1){
		nxt=x/(x/i);
		int u = x / i , r = x % i , SG1 = ser(u) , SG2 = ser(min(u+1,x-1));
		vis[(((i-r)&1)*SG1)^((r&1)*SG2)] = tim;
		if(i<nxt && r>=u) r-=u,i++,vis[(((i-r)&1)*SG1)^((r&1)*SG2)] = tim;
	}
	for(SG[x]=0;vis[SG[x]]==tim;SG[x]++);
	return SG[x];
}

int main(){
	memset(SG,-1,sizeof SG);
	scanf("%d%d",&T,&F);
	for(int i=0;i<F;i++) SG[i]=0;
	SG[1]=0;
	for(;T--;){
		scanf("%d",&n);
		int ans = 0;
		for(int i=1,x;i<=n;i++){
			scanf("%d",&x);
			ans ^= ser(x);
		}	
		if(ans == 0) printf("%d%c",0,T==0?'\n':' ');
		else printf("%d%c",1,T==0?'\n':' ');
	}
}

你可能感兴趣的:(数论,博弈,奇巧淫技)