[SDOI2009]SuperGCD 压位高精度+辗转相减

Posted aloyd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SDOI2009]SuperGCD 压位高精度+辗转相减相关的知识,希望对你有一定的参考价值。

题目链接:

https://www.luogu.org/problemnew/show/P2152

 

题目概述: 

  计算两个大整数(A,B)的最大公因数

数据范围

  0 < A , B ≤ 10 ^

  其一在于辗转相减法——辗转相除法的优化(针对大数,避免了大数的模运算带来的多方面的复杂度)

  思想就是 以数次 A-B  代替 A%B (这二者是等价的)

  辗转相减法:

技术分享图片
 1 /*
 2         Write(X)    输出X
 3         Down(X)   X除以2
 4         Up(X)        X乘以2
 5 */
 6 void Solve(){
 7     int t=0;
 8     int ok=0;
 9     while(A!=B){
10         if(A<B) swap(A,B);
11         int x=A.number[1]%2,y=B.number[1]%2;
12         if(x==0 && y==0){
13             t++;
14             Down(A),Down(B);      
15         }
16         else if(x==0) Down(A);
17         else if(y==0) Down(B);
18         else A=A-B;
19     }
20     while(t--) Up(A);
21     Write(A);
22     return ;
23 }
View Code

  其二就在于压位高精度本身的实现了,我这里选用的是压四位(例如Number[1]=0023,Number[2]=0034表示340023)

  结构体(包括 小于比较;不等于比较;减法)

技术分享图片
 1 #include<map>
 2 #include<queue>
 3 #include<cmath>
 4 #include<cstdio>
 5 #include<cstring>
 6 #include<iostream>
 7 #include<algorithm>
 8 using namespace std;
 9 typedef long long ll;
10 const int Hash=100003;
11 int A,B,N; 
12 int Tot=0;
13 int F[Hash+5];
14 struct data{
15     ll to;
16     int next;
17     ll cost;
18 }E[Hash+5];
19 void Addl(int x,ll y,ll z){
20 //    printf("%d %d %d
",x,y,z);
21     E[++Tot]=(data){y,F[x],z};
22     F[x]=Tot;
23     return ;
24 }
25 int H(ll x){
26     return abs(x%Hash);
27 }
28 int Updata(ll x,int y,ll z){
29     int t=H(x);
30     int i=F[t];
31     while(i){
32         ll c=E[i].to;
33         if(c==x) return E[i].cost;
34         i=E[i].next;
35     }
36     if(y==0) return -1;
37     if(y==1) Addl(t,x,z);
38     return 1;
39 }
40 ll Exgcd(ll a,ll b,ll &x,ll &y){
41     if(b==0){
42         x=1;
43         y=0;
44         return a;
45     }
46     ll res=Exgcd(b,a%b,y,x);
47     y-=a/b*x;
48     return res;
49 }
50 //map<ll,int>mp;
51 void Solve(ll a,ll b,ll c){
52       Tot=0;
53     memset(F,0,sizeof(F));
54     a%=c;
55     ll t=1;
56     ll tmp=1;
57     ll m=sqrt(c);
58     if(m*m<N) m++;
59     Updata(1,1,m+1);
60 //    mp.clear();
61 //    mp[1]=m+1;
62     for(ll i=1;i<m;i++){
63         tmp=(tmp*a)%c;
64         Updata(tmp,1,i);
65         //if(!mp[tmp]) mp[tmp]=i;
66     }
67     tmp=tmp*a%c;
68     ll d=1,x,y;
69     for(ll i=0;i<m;i++){
70         ll x,y;
71         ll res=Exgcd(d,c,x,y);
72         ll need=(b/res*x%c+c)%(c/res);
73         int t=Updata(need,0,-1);
74     //    printf("%d %d<
",need,t);    
75         if(t>0){
76             if(t==m+1) t=0;
77             cout<<i*m+t<<endl;
78             return ;
79         }
80         d=(d*tmp)%c;
81     }
82     printf("-1
");
83     return ;
84 }
85 int main(){
86     while(scanf("%d%d%d",&A,&B,&N)!=EOF)
87      Solve((ll)A,(ll)B,(ll)N);
88     return 0;
89 }
View Code

 

  乘2及除2

技术分享图片
 1 void Up(alpha &x){
 2     int now=1;
 3     while(now<=x.large){
 4         x.number[now]*=2;
 5         now++;
 6     }
 7         
 8     now=1;
 9     while(now<=x.large){
10         if(x.number[now]>=10000) x.number[now]-=10000,x.number[now+1]++;
11         now++; 
12     } 
13      
14     while(x.number[x.large+1]) x.large++;
15     return ;
16 }
17 void Down(alpha &x){
18     int now=x.large;
19     while(now){
20         if(x.number[now]%2) x.number[now-1]+=10000;
21         x.number[now--]/=2;        
22     }
23     while(x.large>1 && !x.number[x.large]) x.large--;
24     return ;
25 }
View Code

 

  读入及输出

技术分享图片
 1 void Read(alpha &x){
 2     alpha a;
 3     char c=getchar();
 4     while(!isdigit(c)) c=getchar();
 5     while(isdigit(c)) a.number[++a.large]=c-0,c=getchar();
 6     x.large=(a.large-1)/4+1;
 7     reverse(a.number+1,a.number+1+a.large);
 8     while(a.large>1 && !a.number[a.large]) a.large--;
 9     while(a.large) x.number[(a.large-1)/4+1]=x.number[(a.large-1)/4+1]*10+a.number[a.large--];
10     return ;
11 }
12 void Write(alpha x){
13     alpha a;
14     int front=1;
15     a.large=4*x.large;
16     while(front<=x.large){
17         for(int i=1;i<=4;i++)
18          a.number[(front-1)*4+i]=x.number[front]%10,x.number[front]/=10;
19         front++;
20     }
21     while(a.large>1 && !a.number[a.large]) a.large--;
22     while(a.large) putchar(a.number[a.large--]+0);
23     putchar(
);
24     return ;
25 }
View Code

 

   

全code

    

技术分享图片
  1 /*
  2     SuperGcd  
  3       LG 1414 
  4 */
  5 #include<queue>
  6 #include<cstdio>
  7 #include<cstring>
  8 #include<iostream>
  9 #include<algorithm>
 10 using namespace std;
 11 struct alpha{
 12     int large;
 13     int number[10005];
 14     alpha(){
 15         large=0;
 16         memset(number,0,sizeof(number));
 17     }
 18     friend bool operator<(alpha a,alpha b){
 19         if(a.large!=b.large) return a.large<b.large;
 20         while(a.large)
 21          if(a.number[a.large]!=b.number[a.large--]) return a.number[++a.large]<b.number[a.large];
 22         return 0;
 23     }
 24     friend bool operator!=(alpha a,alpha b){
 25         if(a.large!=b.large) return 1;
 26         while(a.large)
 27          if(a.number[a.large]!=b.number[a.large--]) return 1;
 28         return 0;
 29     }
 30     friend alpha operator-(alpha a,alpha b){
 31         alpha c;
 32         while(c.large<a.large){
 33             c.number[++c.large]+=a.number[c.large]-b.number[c.large];
 34             while(c.number[c.large]<0) c.number[c.large]+=10000,c.number[c.large+1]--; 
 35         }
 36         while(c.large>1 && !c.number[c.large]) c.large--;
 37         return c;
 38     }
 39 };
 40 void Read(alpha &x){
 41     alpha a;
 42     char c=getchar();
 43     while(!isdigit(c)) c=getchar();
 44     while(isdigit(c)) a.number[++a.large]=c-0,c=getchar();
 45     x.large=(a.large-1)/4+1;
 46     reverse(a.number+1,a.number+1+a.large);
 47     while(a.large>1 && !a.number[a.large]) a.large--;
 48     while(a.large) x.number[(a.large-1)/4+1]=x.number[(a.large-1)/4+1]*10+a.number[a.large--];
 49     return ;
 50 }
 51 void Write(alpha x){
 52     alpha a;
 53     int front=1;
 54     a.large=4*x.large;
 55     while(front<=x.large){
 56         for(int i=1;i<=4;i++)
 57          a.number[(front-1)*4+i]=x.number[front]%10,x.number[front]/=10;
 58         front++;
 59     }
 60     while(a.large>1 && !a.number[a.large]) a.large--;
 61     while(a.large) putchar(a.number[a.large--]+0);
 62     putchar(
);
 63     return ;
 64 }
 65 alpha A,B;
 66 void Up(alpha &x){
 67     int now=1;
 68     while(now<=x.large){
 69         x.number[now]*=2;
 70         now++;
 71     }
 72         
 73     now=1;
 74     while(now<=x.large){
 75         if(x.number[now]>=10000) x.number[now]-=10000,x.number[now+1]++;
 76         now++; 
 77     } 
 78      
 79     while(x.number[x.large+1]) x.large++;
 80     return ;
 81 }
 82 void Down(alpha &x){
 83     int now=x.large;
 84     while(now){
 85         if(x.number[now]%2) x.number[now-1]+=10000;
 86         x.number[now--]/=2;        
 87     }
 88     while(x.large>1 && !x.number[x.large]) x.large--;
 89     return ;
 90 }
 91 void Solve(){
 92     int t=0;
 93     int ok=0;
 94     while(A!=B){
 95         if(A<B) swap(A,B);
 96         int x=A.number[1]%2,y=B.number[1]%2;
 97         if(x==0 && y==0){
 98             t++;
 99             Down(A),Down(B);
100         }
101         else if(x==0) Down(A);
102         else if(y==0) Down(B);
103         else A=A-B;
104     }
105     while(t--) Up(A);
106     Write(A);
107     return ;
108 }
109 int main(){
110     Read(A);Read(B);
111     Solve();
112     return 0;
113 }
View Code

 

对于我这样的蒟蒻来讲,这代码可真是难码。。。。。(不过还是很有成就感就是了)

 

以上是关于[SDOI2009]SuperGCD 压位高精度+辗转相减的主要内容,如果未能解决你的问题,请参考以下文章

bzoj千题计划288:bzoj1876: [SDOI2009]SuperGCD

P2152 [SDOI2009]SuperGCD

[SDOI2009]SuperGCD

[SDOI2009]SuperGCD 高精度GCD

P2152 [SDOI2009]SuperGCD(模拟)

学术篇SDOI2009 SuperGCD