2020 杭电第九场 1003 Slime and Stones 扩展威佐夫博弈 betty定理

2020 杭电第九场 1003 Slime and Stones 扩展威佐夫博弈 betty定理

题目

http://acm.hdu.edu.cn/showproblem.php?pid=6869

题意

有两堆石子,有两种拿取的方式,一:在一堆中拿任意多个石子,二:在两堆中拿相差不能超过k的石子。

题解

首先,我们了解一下威佐夫博弈
他是这样的一种博弈:有两堆各若干个物品,两个人轮流拿物品,有两种拿取的方式,
一:在一堆中拿任意多个物品,
二:在两堆中拿相同多的物品。
最后取光者得胜。

威佐夫博弈就是题目中k==0的特殊情况,那我们先讨论这种特殊情况吧。

我们简单分析一下,会发现一些局面是先手必败的。比如说(0, 0),再比如(1, 2)。
我们简单分析一下(1, 2),先手有4种策略。
1、首先他可以取走第一堆,那么后手可以取完第二堆,显然后手获胜。
2、他也可以在第二堆当中取1个,这时剩下(1, 1),后手会同时取完,同样是后手获胜。
3、第三种是他取走第二堆,后手可以取完第一堆,后手获胜。
4、第四种是他在第一堆和第二堆当中同时取走一个,这时第二堆剩下一个,后手胜。

那么,这些必败的状态之间有什么规律呢? 我们怎么找到这个规律,并且找到解呢?

分析

我们可以枚举几个必败的状态:(0, 0), (1, 2), (3, 5), (4, 7),(6,10)…

我们观察一下这些状态,可以找到两条规律。我们假设从小到大排的第k个必败状态是(x, y),并且x < y。我们可以发现y = x + k。也就是说必败状态两个数的差值是递增的,这也说明了每一个必败状态的差值都各不相同。

其实这是很容易证明的,我们用反证法,假设(a, a+k), (b, b+k)都是必败状态,并且a < b。那么先手在面临(b, b+k)的时候,只需要在两堆当中同时取走b-a个石子,那么给后手的局面就是(a, a+k)。对于后手来说,这是一个必败的局面,这就和(b, b+k)先手必败矛盾,所以不存在两个必败局面的差值相等。

我们也可以作图分析,我们把两堆石子的数量看成是坐标轴上的一个点。
所以游戏就变成了:棋盘上有一个点,每次每个人可以将它向下、向左或者向左下移动若干个格子,不能移动的人输,终止节点显然是原点。

我们根据上面的逻辑把必败点都染色,可以得到下面这张图:

在这里插入图片描述
到这里,我们距离解法已经很接近了,现在剩下的问题是,我们如何根据x和y的取值快速判断它们是否构成一个必败局面呢?也就是说我们能不能找出一个通项公式 ,对于第k个必败局面,它的坐标是(Xk,Yk)呢?

求解

为了写出通项公式,我们需要引入Betty定理

设a和b是两个正无理数,并且在这里插入图片描述

记P={[a* n]|n∈N+} , Q={[b* m]|m∈N+}。则P∩Q = Ø,P∪Q = N+(其中[]符号表示取整数部分)

在这里插入图片描述
第二个证明,这个更加清晰一点:
在这里插入图片描述
我们花了这么大力气来证明Betty定理就是为了用的,因为我们发现必败状态的通项和Betty定理序列很像。我们不妨假设存在这样的a, b同时满足Betty定理与必败状态的性质:
在这里插入图片描述
算出来结果

接下来就讨论一下k=1的情况吧

首先写一下必败态,(1,3)(2,6)(4,10)(5,13)(7,17)…
我们也可以发现他们直接的差值也是递增的,而且是2 4 6 8 10…的递增。
那么我们这个公式不就可以写成 [an]+2n=[bn] 了吗?
化简一下得到 [(a+2)n] = [bn] 然后带入betty定理。得到:
1 a + 1 a + 2 = 1 \frac{1}{a}+\frac{1}{a+2}=1 a1+a+21=1

是不是很容易就可以看出来了,如果k等于其他数,结果就为

1 a + 1 a + k + 1 = 1 \frac{1}{a}+\frac{1}{a+k+1}=1 a1+a+k+11=1

别高兴的太早了。。。我们接下来该计算不同k的情况下,a是多少了

我们直接计算通项公式中的a
1 a + 1 a + k + 1 = 1 \frac{1}{a}+\frac{1}{a+k+1}=1 a1+a+k+11=1
2 a + k + 1 a ( a + k + 1 ) = 1 \frac{2a+k+1}{a(a+k+1)}=1 a(a+k+1)2a+k+1=1
a 2 + ( k − 1 ) a − ( k + 1 ) = 0 {a^2+(k-1)a-(k+1)}=0 a2+(k1)a(k+1)=0

得到 a = ( 1 − k ) + k 2 + 2 k + 5 2 a=\frac{(1-k)+\sqrt{k^2+2k+5}}{2} a=2(1k)+k2+2k+5

好了,大难题结束了,怎么判断给出的两个数是不是必败态呢?

bool lose(int a,int b,int k)
{
	if(b<a)	a^=b^=a^=b;
	int n = (b-a)/(k+1);
	double x = (1-1.0*k+sqrt(1.0*k*k+2.0*k+5.0))/2.0;
	int ans = n*x;
	if(ans==a)
		return true;
	else
		return false;
}

由于精度问题,我们只判断a是不精确的,所以我们也需要判断b,两个条件会更精准

b = a + k + 1 b=a+k+1 b=a+k+1

得到 b = ( 3 + k ) + k 2 + 2 k + 5 2 b=\frac{(3+k)+\sqrt{k^2+2k+5}}{2} b=2(3+k)+k2+2k+5

AC代码

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
using namespace std;
#define ll long long
#define ld long double
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
#define PI acos(-1)
const int maxn = 5e5+5;
const ll mod = 1e9+9;
const double eps = 1e-6L;
bool lose(ll a,ll b,ll k)//由于精度问题,需要判断两个条件更精准
{
	if(a>b) swap(a,b);
	ll n=b-a;
	n/=(k+1);
	ld tmp=sqrt(1.0*k*k+2.0*k+5);
	ld x=(1.0-k+tmp)/2.0,y=(3.0+k+tmp)/2.0;
	if((ll)(x*n)==a&&(ll)(y*n)==b)
		return true;
	else
		return false;
}
int main()
{
	int T=1;
	scanf("%d",&T);
	while(T--)
	{
		ll a,b,k;
		scanf("%lld %lld %lld",&a,&b,&k);
		if(a>b) swap(a,b);
		if(lose(a,b,k)) puts("0");
		else puts("1");
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值