Hdu 1729 Nim博弈

点击打开题目链接

之前没做过这题,因为学弟问到我如果来求该题的sg值,才做了这题。

首先, 是多堆Nim博弈毫无疑问,这题是往一个有固定容量的箱子里放石子,和从一堆石子里面拿出石子是一个道理。

和传统的Nim稍有不同的地方是:The number mustn’t be great than the square of the number of stones before the player adds the stones. 

也就是说,往箱子里放石子的数量应该在1... c^2,当然也应该使放完石子之后箱子里总的石子个数小于S(箱子的容量)。这里,很自然的会想到比较c^2和s-c的大小,s-c是箱子此时剩余的容量,而c^2是可以放的最大的容量(前提是c^2 <= s-c).

所以,如果 c^2 >= s-c ,也就是说此时可以往箱子里放 1...s-c个石子,也就是一个单堆的Nim博弈,所以sg(x) = x。

但是如果 c^2 < s-c, 那么只需要找一个临界的情况,就是 t^2 < s - t 而且 (t+1)^2 >= s - (t+1).这里t是指箱子里当前石子的个数,这里的t是距离终态s最近的一个必败点,终态为s,是因为如果箱子里已经有了s个石子,那么就不可以再往箱子里放石子,所以这个状态是必败态,即sg(s) = 0. 那为什么t状态是必败点呢? 因为从 t+1, t+2, t+3...s-1都可以直接转移到s态,理由就是 (t+1)^2 >= s - (t+1). (能转移到必败点的状态都是必胜态)。所以t状态是距离终态s最近的必败点,也就是说sg(t) = 0。如果, c = t,那么直接返回0, 如果 c > t,那么直接返回sg值,sg(c) = s - c. (因为 sg(s)=0, sg(s-1) = s-1....别忘了单堆Nim的sg(x) = x)。而如果 c < t,那么只需要递归来求sg(c)。道理和上面一样。


附上代码:

 1 /*************************************************************************
 2     > File Name: 1729.cpp
 3     > Author: Stomach_ache
 4     > Mail: sudaweitong@gmail.com 
 5     > Created Time: 2014年04月25日 星期五 11时25分34秒
 6     > Propose: 
 7  ************************************************************************/
 8 
 9 #include <cmath>
10 #include <string>
11 #include <cstdio>
12 #include <fstream>
13 #include <cstring>
14 #include <iostream>
15 #include <algorithm>
16 using namespace std;
17 
18 typedef long long LL;
19 
20 LL
21 get_sg(int s, int c) {
22         int t = int(sqrt(s+0.0));
23         while (t*t+t >= s)
24                 t--;
25         // t+1, t+2 ... s-1 都是必胜态,因为s是必败态,而他们都可以转移到s
26         if (c > t) return s - c;
27         if (c == t) return 0;
28         return get_sg(t, c);
29 }
30 
31 int
32 main(void) {
33         int n, cnt = 1;
34         while (~scanf("%d", &n) && n) {
35                 LL ans = 0;
36                 for (int i = 0; i < n; i++) {
37                         int s, c;
38                         scanf("%d %d", &s, &c);
39                         if (c == 0) continue;
40                         if ((LL)c * c >= s - c) {
41                                 ans ^= (s - c);
42                         } else {
43                                 ans ^= get_sg(s, c);
44                         }
45                 }
46 
47                 printf("Case %d:\n", cnt++);
48                 if (ans) {
49                         puts("Yes");
50                 } else {
51                         puts("No");
52                 }
53         }
54 
55         return 0;
56 }

 


 

转载于:https://www.cnblogs.com/Stomach-ache/p/3703140.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值