Description
有n堆石子,每堆石子有a[i]个。
每次操作可以把某一堆不少于F个的石子堆分成m份(m>=2且m<=a[i]),并且尽量均分。即最多的石子堆和最少的最多相差1.
不能操作者输,求先手是否有必胜策略。
数据组数≤100,n≤100,F,a[i]≤10^5。
Solution
组合游戏。a[i]^2的sg转移还是挺显然的。
那么我们考虑如何优化。
我们发现,我们⌊nm⌋只有n√中可能的取值。
那么我们可以直接分块(分块大法好)
因为我们只关注石子的奇偶性,所以对于同样的取值中我们分成m份和分成m+2份是不会改变每堆石子的奇偶性的。(即不会改变sg值,证明自行脑补)
那么我们只需要堆每个块处理first和first+1就好了。(分块大法好)
加上记忆化,时间复杂度O(NN−−√)
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 100000
using namespace std;
int sg[N+5],mex[N+5],n,x,ty,f,id,ans;
bool bz[N+5];
int get(int x) {
if (x<f) return 0;
if (bz[x]==1) return sg[x];bz[x]=1;
for(int i=2;i<=x;i=x/(x/i)+1) fo(j,i,min(i+1,x))
get(x/j),get(x/j+1);id++;
for(int i=2;i<=x;i=x/(x/i)+1) fo(j,i,min(i+1,x)) {
int nim=0;
if (x%j%2) nim^=sg[x/j+1];
if ((j-x%j)%2) nim^=sg[x/j];
mex[nim]=id;
}
for(sg[x]=0;mex[sg[x]]==id;sg[x]++);
return sg[x];
}
int main() {
scanf("%d%d",&ty,&f);
while (ty--){
scanf("%d",&n);
ans=0;
fo(i,1,n) scanf("%d",&x),ans^=get(x);
if (ans) printf("1");else printf("0");
if (ty) printf(" ");
}
}
Ps:bzoj真神奇,坑了我4发PE。。。
6666666

本文探讨了在有限石子堆中,通过特定操作获得必胜策略的问题,涉及组合游戏和算法优化,提供了时间复杂度为O(N√N)的解决方案。
3872

被折叠的 条评论
为什么被折叠?



