1. 程式人生 > >洛谷 2152 [SDOI2009]SuperGCD

洛谷 2152 [SDOI2009]SuperGCD

數學 opera 但是 -h pac output cin gcd 成了

Description

Sheng bill有著驚人的心算能力,甚至能用大腦計算出兩個巨大的數的GCD(最大公約 數)!因此他經常和別人比賽計算GCD。有一天Sheng bill很囂張地找到了你,並要求和你比 賽,但是輸給Sheng bill豈不是很丟臉!所以你決定寫一個程序來教訓他。

Input

共兩行: 第一行:一個數A。 第二行:一個數B。

Output

一行,表示A和B的最大公約數。

Sample

輸入樣例#1:
12
54
輸出樣例#1:
6

Hints

對於20%的數據,0 < A , B ≤ 10 ^ 18。

對於100%的數據,0 < A , B ≤ 10 ^ 10000。



我的數學可能要完了,我看完數據範圍以後想算一下如果用輾轉相除的話能不能過
我發現我不會算,可是不會其他算gcd的方法了誒
看到題解,發現大家都用了gcd和疑似gcd的方法
我又嘗試算了一下復雜度,這個時候我打開了計算器,可是太大了,會溢出......
然後恍然大悟ToT
Solution
可以寫輾轉相除,但是我不想寫高精取模,但是有一個叫Stein的方法

[1]. 若 aa 為奇數,bb 為偶數,GCD(a, b) = GCD(a, b / 2)GCD(a,b)=GCD(a,b/2)

表示 bb 存在2這個因子而 aa 不存在,則將 bb 除以2,,不考慮因子2;

[2]. 若 aa 為偶數,bb 為奇數,GCD(a, b) = GCD(a / 2, b)GCD(a,b)=GCD(a/2,b)

表示 aa 存在2這個因子而 bb 不存在,則將 aa 除以2,不考慮因子2;

[3]. 若 aa 為偶數,bb 為偶數,GCD(a, b) = GCD(a / 2, b / 2)GCD(a,b)=GCD(a/2,b/2)

表示 a, ba,b 都存在2這個因子,則 GCD(a, b)GCD(a,b) 也存在因子2,則將當前答案乘以2,a, ba,b 都除以2;

[4]. 若 aa 為奇數,bb 為奇數,GCD(a, b) = GCD(a - b, b) (a > b)GCD(a,b)=GCD(ab,b)(a>b)

因為位數太多,所以要壓位,因為只有*2,/2,-的操作,所以可以多壓一點

De了很久的bug

一開始寫的是遞歸版的gcd,暴棧了,遞歸到某一個函數裏時,就會RE

後來發現輸入有問題,不能用getline,會讀空格進來,cin是不讀空格的

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<string>
using namespace std;
const int w=1000000000,wi=9;
struct big{
	int a[2001];
	int len;
	big(){memset(a,0,sizeof(a));len=0;}
	big(string x){        //初始化的時候賦值需要找big(string) 
		*this = x;
	}
	bool operator <(const big&v){
		if(len!=v.len)
		  return len<v.len;
		for(int i=len;i>=1;i--)
		  if(a[i]!=v.a[i])
		    return a[i]<v.a[i];
		return 0;
	}
	big& operator =(string v){
		len=0;int lv=v.length();
		for(int i=lv-1;i>=0;i-=wi)
		{
			int val=0;
			for(int j=max(i-wi+1,0);j<=i;j++)
			  val=val*10+v[j]-‘0‘;      //v[j]寫成了j 
			a[++len]=val;
		}
		return *this;
	}
	big& operator =(big&v){
		len=max(len,v.len);        //取max,因為要把本來有的但是賦值以後沒有的位變成0 
		for(int i=1;i<=len;i++)
		  a[i]=v.a[i];
		while(len&&!a[len]) --len; 
		return *this;
	}
	big& operator -(big&v){
		big res;
		res.len=len;
		for(int i=1;i<=len;i++)
		{
			res.a[i]+=a[i]-v.a[i];
			if(res.a[i]<0)
			{
				res.a[i]+=w;
				res.a[i+1]--;
			}
		}
		while(res.len&&!res.a[res.len]) --res.len;        //res.len不為負
		return res;
	}
	big& operator /(int v){
		big res;
		res.len=len;
		for(int i=len;i>=1;i--)
		{
			res.a[i]=a[i]/v;
		    a[i-1]+=(a[i]-v*res.a[i])*w;
		}
		while(res.len&&!res.a[res.len]) --res.len;
		return res;
	}
	big& operator *(int v){
		big res;
		res.len=len+1;
		for(int i=1;i<=len;i++)
		{
			res.a[i]+=a[i]*2;
			res.a[i+1]+=res.a[i]/w;
			res.a[i]=res.a[i]%w;
		}
		while(res.len&&!res.a[res.len]) --res.len;
		return res;
	}
};
int read()
{
	int ans=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch==‘-‘) f=-1;ch=getchar();}
	while(isdigit(ch)) {ans=ans*10+ch-‘0‘;ch=getchar();}
	return ans*f;
}
big mid;int mi=0;
big gcd(big a,big b)
{
	while(b.len)
	{
		if(a<b)
		{
			mid=a;a=b;b=mid;
		}
		if(!b.len)
	  	  return a;
		if(a.a[1]&1&&b.a[1]&1)
		{
			mid=b;
		    b=a-b;
		    a=mid;
		}
		else if(a.a[1]&1)
		{
			b=b/2;
		}
		else if(b.a[1]&1)
		{
			a=a/2;
		}
		else
		{
			a=a/2;b=b/2;mi++;
		}
	}
	for(int i=1;i<=mi;i++)
	  a=a*2;
	return a;
}
int main()
{
//	freopen("o.txt","r",stdin);
//	freopen("oo.out","w",stdout);
	string a,b;
	cin>>a>>b;       //不能用cin要讀空格
	big a1,b1;
	a1=a;b1=b;
	big ans=gcd(a1,b1);
	for(int i=ans.len;i>=1;i--)
	  if(i==ans.len)
	    printf("%d",ans.a[i]);
	  else
	    printf("%09d",ans.a[i]);
	return 0;
}
/*
111111111111111
111111111111110
*/

洛谷 2152 [SDOI2009]SuperGCD