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.
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函数推导过程在被注释掉的内容里。