首页 > 其他 > 详细

[HNOI2014]江南乐

时间:2019-03-28 11:01:31      阅读:143      评论:0      收藏:0      [点我收藏+]

[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);
    }
}

[HNOI2014]江南乐

原文:https://www.cnblogs.com/lizehon/p/10613431.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!