POJ 2505 A multiplication game(博弈)

题目链接

A multiplication game
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 5935 Accepted: 2962

Description

Stan and Ollie play the game of multiplication by multiplying an integer p by one of the numbers 2 to 9. Stan always starts with p = 1, does his multiplication, then Ollie multiplies the number, then Stan and so on. Before a game starts, they draw an integer 1 < n < 4294967295 and the winner is who first reaches p >= n.

Input

Each line of input contains one integer number n.

Output

For each line of input output one line either 
Stan wins. 
or 
Ollie wins. 
assuming that both of them play perfectly.

Sample Input

162
17
34012226

Sample Output

Stan wins.
Ollie wins.
Stan wins.

Source



博弈练习中。


题意:两个人进行乘法博弈,初始状态数字为1.两个人可以将该数字乘以2~9之间任一数字,优先使乘法结果大于等于n的人获胜。n范围(1,1<<32).


结题思路:dp推sg值,需要注意,一个数字的前驱结点并不是所有小于它的数,而是[ceil(x / 9.0), ceil(x / 2.0)].在此范围外的数字并不是它的前驱(因为游戏玩家绝顶聪明,此范围外的策略均不是最优)。打个表会发现,利己态和利他态交替出现。1为利他态,[2, 9]为利己态,[9+1, 2*9]为利他态,[2*9+1, 2*9*9]为利己态,[2*9*9+1,2*2*9*9]为利他态……以此类推。所以可以直接用循环除法判断一个数在哪个区间,确定其为利己态还是利他态。



这个题我想了一天也没想到正地方,自己一开始写的sg函数有漏洞,后来参考了一下题解,想了想后又自己写了sg函数推导过程,终于明白了。


sg函数推导过程在被注释掉的内容里。


#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <map>
#include <vector>
#include <list>
#include <set>
#include <stack>
#include <queue>
#include <deque>
#include <algorithm>
#include <functional>
#include <numeric>
#include <iomanip>
#include <climits>
#include <new>
#include <utility>
#include <iterator>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <ctime>

using namespace std;



int main()
{
    long long n;
    while (scanf("%I64d", &n) != EOF) {
        while (1)
        {
            n = ceil(n / 9.0);
            if(n == 1ll) {
                printf("Stan wins.\n");
                break;
            }
            n = ceil(n / 2.0);
            if (n == 1ll) {
                printf("Ollie wins.\n");
                break;
            }
        }
    }

    /*
    freopen("out.txt","w",stdout);
    memset(win, 0, sizeof(win));//init
    win[0] = -1;
    win[1] = 0;//lose
    int flag = 0;
    int l,r;
    for (int i = 2; i <=5000; ++i) {
        flag = 0;
        l = int(ceil(i/9.0));
        r = int(ceil(i / 2.0));
        for (int j = l; j <= r; ++j){
            if(win[j] == 0){
                flag = 1;
                break;
            }
        }
        win[i] = flag;
    }
    for(int i = 1; i <= 5000; ++i){
        if(win[i] != win[i-1] || win[i] != win[i+1])
            printf("%5d",i);
    }
    */
    return 0;
}




这个题我想了一天也没想到正地方,自己一开始写的sg函数有漏洞,后来参考了一下题解,想了想后又自己写了sg函数推导过程,终于明白了。


sg函数推导过程在被注释掉的内容里。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值