1. 程式人生 > >[SDOI2009]SuperGCD 【壓位高精度+輾轉相減】

[SDOI2009]SuperGCD 【壓位高精度+輾轉相減】

putc lose 帶來 struct 包括 class hide ron tro

題目鏈接:

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\n",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<\n",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\n"); 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(\n);
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(\n);
 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 【壓位高精度+輾轉相減】