传送门:51nod 1185
3
3 5
3 4
1 9
B
A
A
题目大意:
中文题不解释。需要注意的是题目给的数据比较大 1<= N <=10^18,直接用威佐夫博弈做会产生精度问题,什么是精度问题呢?比如一个大数乘以黄金分割比例0.618…的小数点后9位和小数点后27位得到的结果有可能是不同的,当然乘以小数点后面的数越多结果越精确。
思路:
一般的威佐夫博弈的做法是,两堆石子数分别为a,b,其中a<b,则如果 (b-a)*(sqrt(5)+1)/2的结果与a相等,则B获胜,反之A获胜(A先手)。其中(sqrt(5)+1)/2的值为1.618…其-1的值为0.618…即黄金分割比例。
具体实现:
上面提到,由于是大数,直接乘以(sqrt(5)+1)/2会有精度问题。那么我们就来模拟一下两数之差和(sqrt(5)+1)/2相乘的过程,它等价为:(b-a)*黄金分割比例+(b-a) . 我们用tmp数组存储黄金分割比例的小数点后1~9位、10~18位、19~27位。用l存储(b-a)的高9位,r存储(b-a)的低9位。则两数相乘有:
tmp[0] tmp[1] tmp[2]
* l r
r*tmp[0] r*tmp[1] r*tmp[2]
+ l*tmp[0] l*tmp[1] l*tmp[2]
以上是模拟乘法的过程,只需要把每一位对应的数相加再加上低位,最后加上(b-a)即可。
注:
至于黄金分割比例的27位小数是怎么获取的,这个貌似只能百度吧……有什么好的方法还欢迎留言告知,多谢~
之前有一点一直没想明白,我们要乘以的是黄金分割比0.618…而tmp数组存储的缺是一个27位的大整数。代码中结果却没有明显的再除以10^27的式子。这是怎么回事呢?其实我们需要的是结果的整数部分,最低9位的结果只会对次低9位的结果产生影响,依此类推。所以下面代码在计算结果的时候都是当前位的值加上 次低9位/mod 的值。一共除以了3次,也就相当于让结果共除以了10^27。
代码:
#include<stdio.h>
#include<math.h>
typedef long long LL;
int main()
{
int i,t;
LL a,b,c,d,l,r,sum;
LL mod=1e9;
LL tmp[3]={618033988,749894848,204586834}; //存储黄金分割比例的1~27位
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld",&a,&b);
if(a>b)
{ //保证b>=a
c=a;
a=b;
b=c;
}
d=b-a; //d存储两数之差
l=d/mod; //l存储差的高9位
r=d%mod; //r存储差的低9位
//以下为模拟乘法的过程
sum=r*tmp[2];
sum=r*tmp[1]+l*tmp[2]+sum/mod;
sum=r*tmp[0]+l*tmp[1]+sum/mod;
sum=d+l*tmp[0]+sum/mod; //d+d*黄金分割比例
if(sum!=a) printf("A\n");
else printf("B\n");
}
return 0;
}