HDU 1729 Stone Game(思维 & SG函数)

这是一个两个人玩的游戏,玩家轮流往装有一定大小限制的盒子里放石头,每回合放的石头数不超过当前盒内石头数的平方。当无法再放石头的一方输掉游戏。题目要求根据初始状态判断先手玩家是否必胜。通过sg函数实现策略分析,递归解决。具体策略包括:当tmp小于ci时,考虑所有可能情况;当tmp大于等于ci时,递归处理。最后注意输出格式,避免因惯性思维导致错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem Description
This game is a two-player game and is played as follows:

  1. There are n boxes; each box has its size. The box can hold up to s stones if the size is s.
  2. At the beginning of the game, there are some stones in these boxes.
  3. The players take turns choosing a box and put a number of stones into the box. The number mustn’t be great than the square of the number of stones before the player adds the stones. For example, the player can add 1 to 9 stones if there are 3 stones in the box. Of course, the total number of stones mustn’t be great than the size of the box.
    4.Who can’t add stones any more will loss the game.

Give an Initial state of the game. You are supposed to find whether the first player will win the game if both of the players make the best strategy.

Input
The input file contains several test cases.
Each test case begins with an integer N, 0 < N ≤ 50, the number of the boxes.
In the next N line there are two integer si, ci (0 ≤ ci ≤ si ≤ 1,000,000) on each line, as the size of the box is si and there are ci stones in the box.
N = 0 indicates the end of input and should not be processed.

Output
For each test case, output the number of the case on the first line, then output “Yes” (without quotes) on the next line if the first player can win the game, otherwise output “No”.

Sample Input
3
2 0
3 3
6 2
2
6 3
6 3
0

Sample Output
Case 1:
Yes
Case 2:
No

思维型sg函数,百度一搜一大堆题解理解后还是自己再写一遍为好。

每次往盒子里放得数量不超过当前数量的平方,不能再放的人为输;

找到一个最大的tmp满足:

    tmp + tmp * tmp < si;

这时:

1,tmp < ci, 此时有放满si的方法,通过sg函数的定义我们可以知道下一种情况的可能有0~si-ci+1这些情况,没出现的最小值为si-ci;
2,tmp >= ci,此时递归可解,以为此时最大为si和最大为tmp一样,都会到达能一步放满的情况,所以不断的把tmp当做si向下递归即可。

ac代码:

#include <bits/stdc++.h>

using namespace std;

#define rep(i,a,n) for(int i = (a); i < (n); i++)
#define per(i,a,n) for(int i = (n)-1; i >= a; i--)
#define clr(arr,val) memset(arr,val,sizeof(arr))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define pi acos(-1)
typedef long long LL;
typedef pair<int, int> pii;
const double eps = 1e-8;
const LL mod = 1000000007;
int get_sg(int si, int ci){
    int tmp = (int)sqrt(1.0*si);
    while (tmp + tmp*tmp >= si) tmp--;
    if(tmp < ci) return si - ci;
    else return get_sg(tmp, ci);
}
int main(int argc, char const *argv[]) {
    int n, cas = 1;
    int si, ci;
    while (cin >> n && n) {
        printf("Case %d:\n", cas++);
        int ans = 0;
        while (n--) {
            scanf("%d%d", &si, &ci);
            ans ^= get_sg(si, ci);
        }
        puts(ans ? "Yes" : "No");
    }
    return 0;
}

最后不要惯性思维。。。习惯性写成Case #%d结果wa两次,这题真是不按套路出牌。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值