[luogu]P2152 [SDOI2009]SuperGCD

题目

计算两个大整数的gcd

数据范围:0 < A,B \leq 10^{10000}

分析

即写高精形式的Stein\_gcd()

Stein\_gcd()即是更相损减术的优化,对于x,y首先提取其公共2的幂次,x=2^{m}x_{1},y=2^{m}y_{1}\ =>\ gcd(x,y)=2^{m}gcd(x_1,y_1).

由更相损减术,gcd(x_1,y_1)=gcd(x_1-y_1,y_1),但这种直接计算若两者差值太大则时间复杂度逼近O(n)(n为最大整数的值).注意到gcd(x_1,y_1)值为奇数,则可以通过对x_1,y_1中的2的倍数\div 2减半规模.

x_1==y_1gcd(x_1,y_1)=x_1,否则gcd(x_1,y_1)=gcd(x_1-y_1,y_1)(x_1 > y_1),并对x_1-y_1,y_1进行可能的折半操作

PS:一开始写的函数(*,&)形式,莫名其妙TLE. ヘ(;′Д`ヘ) 

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

const int MAXN = 1e4 + 5;
struct big {
  int num[MAXN], len;
  void init(){
    memset(num, 0, sizeof(num));
    len = 1;
  }
  big operator -(const big &a){
    big res;
    res.init(), res.len = max(len, a.len);
    int i;
    for(i = 1; i <= res.len; i++){
      res.num[i] += num[i] - a.num[i];
      while(res.num[i] < 0) res.num[i] += 10, res.num[i + 1]--;
    }
    while(!res.num[res.len] && res.len > 1) res.len--;
    return res;
  }
  big operator *(const int &x){
    int i;
    big res;
    res.init(), res.len = len;
    for(i = 1; i <= len; i++)
      res.num[i] = num[i] * x;
    for(i = 1; i <= len; i++)
      res.num[i + 1] += res.num[i] / 10, res.num[i] %= 10;
    while(res.num[++res.len] > 9) res.num[res.len + 1] += res.num[res.len], res.num[res.len] %= 10;
    while(!res.num[res.len] && res.len) res.len--;
    return res;
  }
  big operator /(const int &x){
    int i;
    big res;
    res.init(), res.len = len;
    for(i = len; i >= 1; i--)
      res.num[i] = num[i];
    for(i = len; i >= 1; i--)
      res.num[i - 1] += res.num[i] % x * 10, res.num[i] /= x;
    res.num[0] = 0;
    while(!res.num[res.len] && res.len > 1) res.len--;
    return res;
  }
  bool operator <(const big &a){
    if(len != a.len) return len < a.len;
    int i;
    for(i = len; i >= 1; i--)
      if(num[i] != a.num[i]) return num[i] < a.num[i];
    return false;
  }
  bool operator==(const big &a){
    if(len != a.len) return false;
    int i;
    for(i = 1; i <= len; i++) if(num[i] != a.num[i]) return false;
    return true;
  }
  void getprint(){
    int i;
    for(i = len; i >= 1; i--) printf("%d", num[i]); printf("\n");
  }
};
big a, b;
char s[MAXN];
big Stein_gcd(big, big);

int main(){
  int i;
  scanf("%s", s + 1), a.len = strlen(s + 1);
  for(i = 1; i <= a.len; i++)
    a.num[i] = s[a.len - i + 1] - '0';
  scanf("%s", s + 1), b.len = strlen(s + 1);
  for(i = 1; i <= b.len; i++)
    b.num[i] = s[b.len - i + 1] - '0';
  big res = Stein_gcd(a, b);
  res.getprint();
  return 0;
}

big Stein_gcd(big x, big y){
  int i, bit_acc = 0;
  while(x.num[1] % 2 == 0 && y.num[1] % 2 == 0)
    bit_acc++, x = x / 2, y = y / 2;
  while(x.num[1] % 2 == 0) x = x / 2;
  while(y.num[1] % 2 == 0) y = y / 2;
  while(!(x == y)){
    if(x < y) swap(x, y);
    x = x - y;
    while(x.num[1] % 2 == 0) x = x / 2;
  }
  while(bit_acc--) x = x * 2;
  return x;
}

猜你喜欢

转载自blog.csdn.net/Hardict/article/details/82698224