[BZOJ1874][BeiJing2009 WinterCamp]取石子游戏(博弈SG函数)

题目描述

传送门

题解

用SG函数求出来NP局面;必胜态的话枚举一下最小的即可。

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

const int max_n=15;
const int max_m=15;
const int max_sg=1005;

int n,m,k;
int a[max_n],rule[max_m];
int sg[max_sg];
bool ext[max_sg];

inline void get_sg(){
    memset(sg,0,sizeof(sg));
    for (int i=1;i<=1000;++i){
        memset(ext,0,sizeof(ext));
        for (int j=1;j<=m;++j){
            if (i-rule[j]<0) break;
            ext[sg[i-rule[j]]]=true;
        }
        for (int j=0;;j++)
          if (!ext[j]){
            sg[i]=j;
            break;
          }
    }
}

int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;++i)
      scanf("%d",&a[i]);
    scanf("%d",&m);
    for (int i=1;i<=m;++i)
      scanf("%d",&rule[i]);
    sort(rule+1,rule+m+1);

    get_sg();

    k=0;
    for (int i=1;i<=n;++i)
      k^=sg[a[i]];
    if (!k) printf("NO\n");
    else printf("YES\n");

    for (int i=1;i<=n;++i){
        k^=sg[a[i]];
        for (int j=1;j<=m;++j){
            if (a[i]-rule[j]<0) break;
            if (!(k^sg[a[i]-rule[j]])){
                printf("%d %d\n",i,rule[j]);
                return 0;
            }
        }
        k^=sg[a[i]];
    }
}

你可能感兴趣的:(wc,博弈,bzoj)