[BZOJ1874][BeiJing2009 WinterCamp]取石子游戏

[BeiJing2009 WinterCamp]取石子游戏

Description
小H和小Z正在玩一个取石子游戏。 取石子游戏的规则是这样的,每个人每次可以从一堆石子中取出若干个石子,每次取石子的个数有限制,谁不能取石子时就会输掉游戏。 小H先进行操作,他想问你他是否有必胜策略,如果有,第一步如何取石子。
Input
输入文件的第一行为石子的堆数N 接下来N行,每行一个数Ai,表示每堆石子的个数 接下来一行为每次取石子个数的种类数M 接下来M行,每行一个数Bi,表示每次可以取的石子个数,输入保证这M个数按照递增顺序排列。
Output
输出文件第一行为“YES”或者“NO”,表示小H是否有必胜策略。 若结果为“YES”,则第二行包含两个数,第一个数表示从哪堆石子取,第二个数表示取多少个石子,若有多种答案,取第一个数最小的答案,若仍有多种答案,取第二个数最小的答案。
Sample Input
4
7
6
9
3
2
1
2
Sample Output
YES
1 1
Hint
样例中共有四堆石子,石子个数分别为7、6、9、3,每人每次可以从任何一堆石子中取出1个或者2个石子,小H有必胜策略,事实上只要从第一堆石子中取一个石子即可。
数据规模和约定
数据编号 N范围 Ai范围 数据编号 N范围 Ai范围
1 N=2 Ai≤10 6 N≤10 Ai≤10
2 N=2 Ai≤1000 7 N≤10 Ai≤100
3 N=3 Ai≤100 8 N≤10 Ai≤1000
4 N≤10 Ai≤4 9 N≤10 Ai≤1000
5 N≤10 Ai≤7 10 N≤10 Ai≤1000
对于全部数据,M≤10,Bi≤10

Solution
SG函数裸题

Code

#include <bits/stdc++.h>
using namespace std;

#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define MS(_) memset(_, 0, sizeof(_))
#define MP make_pair
#define PB push_back
typedef long long ll;
typedef pair<int, int> PII;
template<typename T> inline void read(T &x){
    x = 0; T f = 1; char ch = getchar();
    while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
    while (isdigit(ch))  {x = x * 10 + ch - '0'; ch = getchar();}
    x *= f;
}

int n, stone[15], m, operate[15], cnt[15], mex[1010], sg;
inline void ckmax(int &x, int y){if (x < y) x = y;}
int main(){
    read(n);
    rep(i, 1, n) read(stone[i]);

    read(m);
    rep(i, 1, m) read(operate[i]);

    rep(i, 1, 1000){ MS(cnt); int j;
        for (j = 1; j <= m && i-operate[j]>=0; j++)  cnt[mex[i-operate[j]]]++;
        for (j = 0; cnt[j]; j++);
        mex[i] = j;
    }

    rep(i, 1, n) sg ^= mex[stone[i]];
    if (sg == 0) puts("NO");
    else{
        puts("YES");
        rep(i, 1, n) rep(j, 1, m)
            if (mex[stone[i]-operate[j]] == (sg^mex[stone[i]])){
                printf("%d %d\n", i, operate[j]);
                return 0;
            }
    }

    return 0;
}

你可能感兴趣的:(博弈,sg函数)