【bzoj3576】【HNOI2014】江南乐

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

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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值