1. 程式人生 > >[BZOJ3576]江南樂

[BZOJ3576]江南樂

tchar amp 記憶 1-n include urn 想法 har 其中

挺好的題

我們算出每個數的sg值後異或起來即可

對於$n$,我們要求$sg_n$

樸素的想法是枚舉把$n$個石子分成$m$堆,有$m-n\%m$堆大小為$\left\lfloor\frac nm\right\rfloor$的石子,有$n\%m$堆大小為$\left\lfloor\frac nm\right\rfloor+1$的石子,因為是異或所以只有奇數堆的石子對$sg_n$有貢獻,直接算出來再求mex即可

考慮優化,暴力是枚舉$2\leq m\leq n$,因為當$\left\lfloor\frac nm\right\rfloor$相同時奇偶性相同的$m$算出來的答案是一樣的,所以我們只需枚舉所有使得$\left\lfloor\frac nm\right\rfloor$不同的$m$,用$m$和$m+1$更新答案即可

用記憶化搜索記錄答案即可,時間復雜度可能是$O\left(a\sqrt a\right)$,其中$a$是數字的大小

#include<stdio.h>
#include<string.h>
int f[100010],v[1000010],M,F;
void get(int n){
	if(~f[n])return;
	if(n<F){
		f[n]=0;
		return;
	}
	int i,nex,s;
	for(i=2;i<=n;i=nex+1){
		nex=n/(n/i);
		if(f[n/i]==-1)get(n/i);
		if(n!=2&&f[n/i+1]==-1)get(n/i+1);
	}
	M++;
	for(i=2;i<=n;i=nex+1){
		nex=n/(n/i);
		s=0;
		if(n%i&1)s^=f[n/i+1];
		if((i-n%i)&1)s^=f[n/i];
		v[s]=M;
		if(i<nex){
			s=0;
			if(n%(i+1)&1)s^=f[n/i+1];
			if((i+1-n%(i+1))&1)s^=f[n/i];
			v[s]=M;
		}
	}
	for(i=0;v[i]==M;i++);
	f[n]=i;
}
int main(){
	int T,n,x,s;
	scanf("%d%d",&T,&F);
	memset(f,-1,sizeof(f));
	while(T--){
		scanf("%d",&n);
		s=0;
		while(n--){
			scanf("%d",&x);
			get(x);
			s^=f[x];
		}
		putchar(s?‘1‘:‘0‘);
		putchar(‘ ‘);
	}
}

[BZOJ3576]江南樂