HDU 1517 A Multiplication Game (博弈、PN态、找规律)*

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1517


题意:从p=1开始Stan和Ollie各取一个2到9之间的数乘以p直到最先到达p>=n的胜利。

1、找规律:


①、如果输入是2~9,因为Stan是先手,所以Stan必胜。


②、如果输入是10~18(9*2),因为Ollie是后手,不管第一次Stan乘的是多少,Stan肯定在2~9之间,如果Stan乘以2,那么Ollie就乘以9,那么Ollie乘以大于1的数都能超过10~18中的任何一个数,Ollie必胜。


③、如果输入的是19~162(9*2*9),那么这个范围Stan必胜。


④、如果输入是163~324(9*2*9*2),这个是Ollie的必胜范围。

…………


这样一种状态只要除以18就可以转化为上一个同种状态。因为我们只需判断范围就可以了,所以直接用浮点数即可达到效果。

所以一直除到状态①和状态②然后判断一下就可以了。


#include <iostream> 
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
int main() {
	double n;
	while(~scanf("%lf", &n)) {
		while(n > 18) n = n / 18;
		if(n > 9) puts("Ollie wins.");
		else puts("Stan wins.");
	}
	return 0;
}


2、分析必胜态和必败态

由于每次都是从p=1开始的,所以只要判断每个游戏中1为必败点还是必胜点即可。
依照上面所提到的算法,将终结位置,即[n,无穷]标记为必败点;
然后将所有一步能到达此必败段的点标记为必胜点,即[n/9,n-1]为必胜点;
然后将只能到达必胜点的点标记为必败点,即[n/9/2,n/9-1]为必败点;
重复上面2个步骤,直至可以确定1是必胜点还是必败点。


#include <iostream> 
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
int main() {
	ll n;
	while(~scanf("%I64d", &n)) {
		int turn = 1; //必胜态和必败态是交替进行的 
		while(n > 1) {
			if(turn&1) {
				if(n % 9) n = n / 9 + 1; //除不尽要进行上取整 
				else n = n / 9;
			}
			else {
				if(n % 2) n = n / 2 + 1;
				else n = n / 2;
			}
			turn++;
		}
		if(turn&1) puts("Ollie wins.");
		else puts("Stan wins.");
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值