codeforces 399 E. Game of Stones 博弈 思维题

来源:互联网 发布:计算机二级vb视频教程 编辑:程序博客网 时间:2024/06/05 16:55

题目地址

http://codeforces.com/contest/768/problem/E

题意

1<=n<=1e6堆石子,每堆石子个数为1<=s<=60,每次选一堆石子,取走任意石子(不能为0),唯一的限制条件是对某堆石子,每次取走的石子数不能重复,当一方不能取走任意石子时,此方判输,问双方均采用最优策略的胜负情况

思路

官方题解的思路是计算每个s值对应的sg函数,因为s值只有60种不同的情况,所以计算量不是很大。但是现在看到的很多代码都是把max(x|xi=0i<=s)作为s的sg值。
看了看cf题解下的讨论,大致的证明思路是这样的:一堆石子不能取重复的石子数,那么这堆石子最多可以被取x次,因为可以把这堆石子分成x份,每份的个数分别为1, 2, …, x - 1, x个,一次操作就是从这些石子中任取几份。这样题目就退化成了一般的nim博弈:一堆石子有x个,每次取不为0任意的石子数,不能取的一方判输。
然后统计所有的石子堆的异或和就好了。
遇到博弈题,的确应该一步步从sg值出发来考虑问题。

代码

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;int sg[70];int n;int main() {    int now = 1, tot = 1, nxt = 2;    for (; tot <= 60; ++nxt) {        while (tot <= 60 && now + nxt > tot) sg[tot++] = nxt - 1;        now += nxt;    }//    for (int i = 0; i <= 60; ++i) cout<<i<<": "<<sg[i]<<endl;    while (~scanf("%d", &n)) {        int ans = 0;        int x;        for (int i = 0; i < n; ++i) {            scanf("%d", &x);            ans ^= sg[x];        }        if (ans) puts("NO");        else puts("YES");    }}
1 0
原创粉丝点击