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

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 

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两次,这题真是不按套路出牌。。。

你可能感兴趣的:(=====博弈=====,=====思维=====)