[HNOI2014]江南乐

本文介绍了一种计算SG值的方法,特别是针对将一定数量的石子分成不同堆数的情况。通过分析堆数的奇偶性和整除分块,可以高效地求解SG值。

[Luogu3255] [LOJ2210]

所有后继状态的\(SG\)值异或起来等于当前状态的\(SG\)

\(x\)个石子分成\(i\)
我们可以发现最后有\(x % i\)堆分到了\(\lfloor\frac{x}{i}\rfloor+1\)个石子,有\(i-x%i\)堆分到了\(\lfloor\frac{x}{i}\rfloor\)个石子 , 只需要考虑堆数的奇偶即可

又发现分成\(i\)堆和分成\(i+2\)堆是等价的,所以对于同一个块只要烤绿最前面的两个值即可

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define Debug(x) cout<<#x<<"="<<x<<endl
using namespace std;
typedef long long LL;
const int INF=1e9+7;
inline LL read(){
    register LL x=0,f=1;register char c=getchar();
    while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
    while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
    return f*x;
}

const int N=1e5+5;

int sg[N],mex[N];
int T,F;

inline int getsg(int x){
    if(~sg[x]) return sg[x];
    if(x<F) return sg[x]=0;
    sg[x]=0;
    for(int i=2;i<=x;i=x/(x/i)+1){//分成i堆,整除分块
        for(int j=i;j<=min(i+1,x);j++){//只要考虑前两个数
            int tmp=0;
            if((x%j)&1) tmp^=getsg(x/j+1);
            if((j-x%j)&1) tmp^=getsg(x/j);
            mex[tmp]=x;
        }
    }
    while(mex[sg[x]]==x) sg[x]++;//后继的补集中最大的数
    return sg[x];
}

int main(){
    T=read(),F=read();
    memset(sg,-1,sizeof sg);
    while(T--){
        int ans=0;
        for(int i=read();i;i--) ans^=getsg(read());
        printf("%d ",(bool)ans);
    }
}

转载于:https://www.cnblogs.com/lizehon/p/10613431.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值