zoukankan      html  css  js  c++  java
  • [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

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

  • 相关阅读:
    Unity3D实践系列08, MonoBehaviour类的各种触发事件
    Unity3D实践系列07,组件的启用或禁用开关,物体的的可见或不可见开关,以及相应事件
    Unity3D实践系列06,球体撞击物体游戏
    Linux tee的花式用法和pee
    bash内置命令mapfile:读取文件内容到数组
    Perl正则表达式引用
    Perl文件句柄引用
    透明代理、正向代理、反向代理的区别说明
    Perl回调函数和闭包
    一文搞懂:词法作用域、动态作用域、回调函数、闭包
  • 原文地址:https://www.cnblogs.com/Aloyd/p/9296506.html
Copyright © 2011-2022 走看看