[BZOJ3576][Hnoi2014]江南乐
传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=3576
这个题一看就是SG函数那套理论的题……
SG函数的转移也挺好推的
考虑每个游戏单独的SG函数,各组游戏之间没有影响
对于每个i,因为两堆石子间的差距最多为1 每个石子有$O(n)$种分割
然后我们如果直接xjb暴力转移的话是$O(n^2)$的 只能拿到70分
怎么办呢?
发现 每一堆石子只会被分成[$\frac{n}{i}$]和[$\frac{n}{i}$]+1两种取值
如果学过整除分块的同学就会发现 这不是整除分块裸题吗?
整除分块一下,只有$\sqrt n$种取值
然后对两种数量的石子的堆数计算一下 根据异或的性质计算答案
总时间效率$O(n\sqrt n)$
code:
#include <bits/stdc++.h> using namespace std; int SG[100005],mex[100005],N; int T,f; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int Get_SG(int x){ if (SG[x]!=-1) return SG[x]; if (x<f) { SG[x]=0; return 0; } SG[x]=0; for (int j=2,r;j<=x;j=x/(x/j)+1){ for (int i=j;i<=min(j+1,x);i++){ int res=0,a=i-x%i,y=x%i,c; if (y&1) c=Get_SG(x/i+1),res^=c; if (a&1) c=Get_SG(x/i),res^=c; mex[res]=x; } } while (mex[SG[x]]==x) SG[x]++; return SG[x]; } int main(){ //freopen("game.in","r",stdin); //freopen("game.out","w",stdout); T=read(),f=read(); memset(SG,-1,sizeof(SG)); while (T--){ N=read(); int ans=0; for (int i=1;i<=N;i++){ int a; a=read(); ans^=Get_SG(a); } printf("%d ",ans?1:0); } return 0; }
干啥啥不行