SG函数 Alice and Bob

来源:互联网 发布:绝仁弃义 知乎 编辑:程序博客网 时间:2024/04/30 16:41

题目大意是给定n的石子堆,每次只能从一个堆中取石子,每次取得石子不能少于该堆的一半,为先手能不能赢


方法一 暴力DFS:

直接爆搜sg

#include <iostream>#include <cstring>#include <iostream>#include <cstdio>#define MEM(a,x) memset(a,x,sizeof(a))using namespace std;int gcd(int a,int b){  return b==0?a:gcd(b,a%b);  }typedef long long llt ;const int maxn = 3000;int sg[maxn]={0};bool flag[maxn];int getSG(int depth){    if ( -1 != sg[depth] ) return sg[depth];    int l = (int)(depth/2.0+0.5);    for (int i = depth ;i >= l;--i)        flag[ getSG(depth-i)] = true;    for (int i = 0;i < maxn;++i)        if ( !flag[i] )            return i;}void init(){    fill(sg,sg+maxn,-1);    sg[0] = 0;    for (int i = 1;i < maxn;++i){        MEM(flag,0);        sg[i] = getSG(i);    }}int main(){    init();    int n;    while(scanf("%d",&n)&&n){        int x;        int ans = 0;        for (int i = 0;i < n;++i){            scanf("%d",&x);            ans ^= sg[x];        }        if (ans)printf("YES\n");        else printf("NO\n");    }    return 0;}

方法二找 sg的规律

0 1 22 3333 44444444

2的n次方递增

const int maxn = 2050;int sg[maxn];void sieve(){    sg[0] = 0;    sg[1] = 1;    int temp = 2;    for (int i = 2; i < maxn;++i){        int j = 0;        for (;j+i < maxn && j < (1<<(temp-1));++j)            sg[i+j] = temp;        temp++;        i += j - 1;    }}int main(){    sieve();    int n;    while(scanf("%d",&n)&&n){        int x;        int ans = 0;        for (int i = 0;i < n;++i){            scanf("%d",&x);            ans ^= sg[x];        }        if (ans)printf("YES\n");        else printf("NO\n");    }    return 0;}

0 0