[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 }

  其二就在于压位高精度本身的实现了,我这里选用的是压四位(例如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 }

  乘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 }

  读入及输出

 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 }

   

全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 }

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

原文地址:https://www.cnblogs.com/Aloyd/p/9296506.html

时间: 2024-11-03 22:13:10

[SDOI2009]SuperGCD 【压位高精度+辗转相减】的相关文章

[SDOI2009][BZOJ1876] SuperGCD|高精度|更相减损术

1876: [SDOI2009]SuperGCD Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 1970  Solved: 663[Submit][Status][Discuss] Description Sheng bill有着惊人的心算能力,甚至能用大脑计算出两个巨大的数的GCD(最大公约 数)!因此他经常和别人比赛计算GCD.有一天Sheng bill很嚣张地找到了你,并要求和你比 赛,但是输给Sheng bill岂不是很丢脸!所以你决定写一个

辗转相减求最大公约数

#include <iostream> int main() { using namespace std; int m, n; cin >> n >> m; while (m != n) { while (m>n) { m = m - n; } while (n>m) { n = n - m; } } printf("%d\n", m); system("pause"); return 0; } 运行结果:

[BZOJ1876][SDOI2009]superGCD(高精度)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1876 分析: 以为辗转相减会TLE呢……但是好像没这个数据……就这么水过去了…… 辗转相减求a,b的gcd其实可以优化的: 1.若a为偶数,b为奇数:gcd(a,b)=gcd(a/2,b) 2.若a为奇数,b为偶数:gcd(a,b)=gcd(a,b/2) 3.若a,b都是偶数:gcd(a,b)=2*gcd(a/2,b/2) 3.若a,b都是奇数:gcd(a,b)=gcd(a-b,b)

用到了卡特兰数的性质,还有高精度压位,筛法找素数

一列火车n节车厢,依次编号为1,2,3,-,n. 每节车厢有两种运动方式,进栈与出栈,问n节车厢出栈的可能排列方式有多少种. 输入格式 输入一个整数n,代表火车的车厢数. 输出格式 输出一个整数s表示n节车厢出栈的可能排列方式数量. 数据范围 1≤n≤60000 输入样例: 3 输出样例: 5 这道题的本质是卡特兰数 卡特兰数介绍(引用math73) 筛法求素数 最重要的是如何求解组合数,压位思想,还有组合数C(2n)(n)这个式子展开以后,用上下同时除以连续的质数的方法,将答案一点一点凑出来,

C语言复习---获取最大公约数(辗转相除法和更相减损法)

源自:百度百科 辗转相除法 辗转相除法:辗转相除法是求两个自然数的最大公约数的一种方法,也叫欧几里德算法. 例如,求(319,377): ∵ 319÷377=0(余319) ∴(319,377)=(377,319): ∵ 377÷319=1(余58) ∴(377,319)=(319,58): ∵ 319÷58=5(余29) ∴ (319,58)=(58,29): ∵ 58÷29=2(余0) ∴ (58,29)= 29: ∴ (319,377)=29. 用辗转相除法求几个数的最大公约数,可以先求出

BZOJ 1876: [SDOI2009]SuperGCD( 更相减损 + 高精度 )

更相减损,要用高精度.... --------------------------------------------------------------- #include<cstdio> #include<cstring> #include<cctype> #include<algorithm> using namespace std; const int maxn = 10009; char S[maxn]; int Power[maxn]; stru

高精度——压位的思想及应用

本文作者frankchenfu,blogs网址http://www.cnblogs.com/frankchenfu/,转载请保留此文字. 这里我们简单介绍一下高精度的计算. 我们都知道在Cpp/C/Pas等语言中,整数最大能储存\(2^{64} -1\),超过这个范围就表示不了了(不包括个别支持int128的编译器).这个时候,我们如果希望把这些整数存储下来,就需要用到高精度的算法和思想.高精度就是像小学学过的竖式运算一样的(除法除外).然后就直接模拟即可.除法一位一位地试商即可. 接下来我们发

高精度压位

压位的原因 正常的高精度计算中,每一位只存了一位数字,可是当面对比较大的计算的时候呢,如果说每一位都只存一位数字,那么计算的时间就会比较地长.这个时候可以通过每一位高精度中存储多位数字的方法来降低运算的时间 例题引入 简单的来说就是 一个高精度的开根号,只要求开到整数向下取整就可以了.数据范围是10^1000; 首先就是开高精度根号的方法,很容易想到的方法就是二分或者是手动开根号.我这里使用的是二分的方法. 这一道题最开始我是直接高精度来的,然后TLE了,接着我压了四位,还是TLE了,然后直接1

codevs 3119 高精度练习之大整数开根 (各种高精+压位)

/* codevs 3119 高精度练习之大整数开根 (各种高精+压位) 二分答案 然后高精判重 打了一个多小时..... 最后还超时了...压位就好了 测试点#1.in 结果:AC 内存使用量: 256kB 时间使用量: 0ms 测试点#2.in 结果:AC 内存使用量: 256kB 时间使用量: 1ms 测试点#3.in 结果:AC 内存使用量: 256kB 时间使用量: 0ms 测试点#4.in 结果:AC 内存使用量: 256kB 时间使用量: 10ms 测试点#5.in 结果:AC 内