51nod 1185 威佐夫游戏 V2 (用乘法模拟解决大数精度问题)

来源:互联网 发布:天音淘宝宝贝复制软件 编辑:程序博客网 时间:2024/05/16 01:46

传送门:51nod 1185


Input示例
33 53 41 9
Output示例
BAA


题目大意:中文题不解释。需要注意的是题目给的数据比较大 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;}

原创粉丝点击