bzoj1876-更相减损术

题目描述

Sheng bill有着惊人的心算能力,甚至能用大脑计算出两个巨大的数的GCD(最大公约 数)!因此他经常和别人比
赛计算GCD。有一天Sheng bill很嚣张地找到了你,并要求和你比 赛,但是输给Sheng bill岂不是很丢脸!所以你
决定写一个程序来教训他。

输入

共两行: 第一行:一个数A。 第二行:一个数B。
0 < A , B ≤ 10 ^ 10000。

输出

一行,表示A和B的最大公约数。

样例输入

12
54

样例输出

6
 
这道题显然不能用欧几里得来做(高精度取模,乘,除)
根据数学Ⅲ,我们知道了更相损减术的做法

原文:可半者半之,不可半者,副置分母、子之数,以少减多,更相减损,求其等也。以等数约之。

操作:

  1. 任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。
  2. 以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。

优化:

  在每次减好之后都对能除2的除2,若2个都能除2,同除2,gcd*2,(我也不知道为什么会快,但数据跑出来就是这样,(求教~~~))

//转自XT大佬

放一个基础代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int GX_gcd(int a,int b)
{
    int tot,tt;
    if(b==0||a==0) return max(a,b);
    for(tot=0;a%2==0&&b%2==0;tot++,a/=2,b/=2);
    if(a%2==0) a/=2;
    else if(b%2==0) b/=2;
    if(a>b) tt=GX_gcd(a-b,b);else tt=GX_gcd(a,b-a);
    for(int i=1;i<=tot;i++)
    tt=tt*2;
    return tt;
}
int main()
{
    int n,m;
      scanf("%d %d",&n,&m);
    cout<<GX_gcd(n,m)<<endl;        
}

这个不是高精度的

高精度且非递归见下

while(1)
    {
        if((a.nu[1]%2==0)&&(b.nu[1]%2==0)){a.div2();b.div2();num++;}
        else if((a.nu[1]%2==0)) a.div2();
        else if((b.nu[1]%2==0)) b.div2();
        if(a>b){a=a-b; if(a.z()){while(num--)b.mul2();b.out();break;}}
        else {b=b-a; if(b.z()){while(num--)a.mul2();a.out();break;}}
    }

这里采用了位压的手段,a.nu[x]表示a上的第x个块的数字
放一个hzw大神的代码

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #define inf 1000000000
  5 using namespace std;
  6 char ch1[10005],ch2[10005];
  7 int la,lb,cnt;
  8 struct data{int a[1205],l;}a,b;
  9 bool com()
 10 {
 11     if(a.l<b.l)return 0;
 12     if(a.l>b.l)return 1;
 13     for(int i=a.l;i>0;--i)
 14         if(a.a[i]>b.a[i])return 1;
 15         else if(a.a[i]<b.a[i])return 0;
 16     return 1;
 17 }
 18 void print(data a)
 19 {
 20     while(a.a[a.l]==0)a.l--;
 21     for(int i=a.l;i>0;--i)
 22         if(i==a.l)printf("%d",a.a[i]);
 23         else printf("%09d",a.a[i]);
 24 }
 25 inline data sub(data a,data b)
 26 {
 27     int k;
 28     data c;
 29     for(int i=1;i<=1200;++i)
 30     {
 31        if(i<=b.l)c.a[i]=a.a[i]-b.a[i];
 32        else if(i<=a.l)c.a[i]=a.a[i];
 33        else c.a[i]=0;
 34        if(c.a[i]<0)
 35        {
 36           c.a[i]+=inf;
 37           a.a[i+1]--;
 38        }
 39     }
 40     c.l=a.l;
 41     while(c.a[c.l]==0&&c.l)c.l--;
 42     return c;
 43 }
 44 void diva()
 45 {
 46     for(int i=1;i<=a.l;i++)
 47     {
 48         if(a.a[i]&1)a.a[i-1]+=inf/2;
 49         a.a[i]>>=1;
 50     }
 51     if(!a.a[a.l])a.l--;
 52 }
 53 void divb()
 54 {
 55     for(int i=1;i<=b.l;i++)
 56     {
 57         if(b.a[i]&1)b.a[i-1]+=inf/2;
 58         b.a[i]>>=1;
 59     }
 60     if(!b.a[b.l])b.l--;
 61 }
 62 void mul()
 63 {
 64     for(int i=a.l;i>0;i--)
 65     {
 66        a.a[i]<<=1;
 67        a.a[i+1]+=a.a[i]/inf;
 68        a.a[i]%=inf;
 69     }
 70     while(a.a[a.l]>0)a.l++;
 71     for(int i=b.l;i>0;i--)
 72     {
 73        b.a[i]<<=1;
 74        b.a[i+1]+=b.a[i]/inf;
 75        b.a[i]%=inf;
 76     }
 77     while(b.a[b.l]>0)b.l++;
 78 }
 79 int main()
 80 {
 81     scanf("%s%s",ch1+1,ch2+1);
 82     la=strlen(ch1+1);lb=strlen(ch2+1);
 83     if(la%9)a.l=la/9+1;
 84     else a.l=la/9;
 85     if(lb%9)b.l=lb/9+1;
 86     else b.l=lb/9;
 87     for(int i=1;i<=a.l;++i)
 88     {
 89         int k1=max(1,la-i*9+1),k2=la-(i-1)*9;
 90         for(int j=k1;j<=k2;++j)
 91             a.a[i]=a.a[i]*10+ch1[j]-'0';
 92     }
 93     for(int i=1;i<=b.l;++i)
 94     {
 95         int k1=max(1,lb-i*9+1),k2=lb-(i-1)*9;
 96         for(int j=k1;j<=k2;++j)
 97             b.a[i]=b.a[i]*10+ch2[j]-'0';
 98     }
 99     while(1)
100     {
101         if((a.a[1]%2==0)&&(b.a[1]%2==0)){diva();divb();cnt++;}
102         else if((a.a[1]%2==0))diva();
103         else if((b.a[1]%2==0))divb();
104         if(com()){a=sub(a,b);if(!a.l){while(cnt--)mul();print(b);break;}}
105         else {b=sub(b,a);if(!b.l){while(cnt--)mul();print(a);break;}}
106     }
107     //system("pause");
108     return 0;
109 }

其中对于压位后前导0的输出有很大的问题(压九位)
这里用了printf的神奇功能:printf("%09d",i);即可!

神奇的c++!

 

 

 

 
 
 
 
 
 
 
 
 
 
posted @ 2017-05-07 12:21  dancer16  阅读(371)  评论(0编辑  收藏  举报
描述