[SDOI2009]SuperGCD

题解:

       今天XJ考试的时候放了这道题的削弱版:n<=1000。于是想用辗转相减求解。这样显然会炸就考虑使用倍增:假设a<=b,倍增求出一个最大的2的幂2^k,使之乘以a不大于b,然后将两个数变为:(b-a*2^k,a),复杂度是O(n^2*log),还只用打高精减法和高精乘2,岂不是很稳。结果后来TLE了。之后又算了一下复杂度,n^2*log(2,b/a),极限数据下(比如a是一位数),b/a是1e1000数量级的,也就是说这个log可以到3000+的数量级,比n还大!TLE就是稳稳的了。

       后来看了一下题解,有一个有用的性质,正确性非常显然:

              a % 2 = 0, b % 2 = 0,则(a,b)=2*(a/2,b/2)

              a % 2 = 0, b % 2 = 1,则(a,b)=(a/2,b)

              a % 2 = 1, b % 2 = 0,则(a,b)=(a,b/2)

              a % 2 = 1, b % 2 = 1,则(a,b)=(b-a,a) (b>=a)

       只要高精模拟上面的过程就好了,如果TLE的话可以考虑压位。

       压位高精输出的时候中间位数不要忘记前导零!!!

TLE代码:

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<time.h>
#include<vector>
#include<cstring>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int N=1e4+10;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
 
char s[N];
struct BigData {
    int len,a[N];
 
    void Init() {
        len=1;
        memset(a,0,sizeof(a));
    }
     
    void read() {
        scanf("%s",s+1);
        len=strlen(s+1);
        for (register int i=1;i<=len;i++) a[i]=s[len-i+1]-'0';
    }
     
    void write() {
        for (register int i=len;i>=1;i--) putchar(a[i]+'0');
    }
 
    bool operator < (const BigData &other) const {
        if (len<other.len) return 1;
        if (len>other.len) return 0;
        for (register int i=len;i>=1;i--) {
            if (a[i]!=other.a[i])
                return a[i]<other.a[i];
        }
        return 0;
    }
 
    void Get_Double() {
        for (register int i=1;i<=len;i++) a[i]<<=1;
        a[len+1]=a[len+2]=0;
        for (register int i=1;i<=len;i++) {
            if (a[i]>=10) a[i]-=10,a[i+1]+=1;
        }
        if (a[len+1]) len++;
    }
 
    BigData operator - (const BigData &other) const {
        BigData ans; ans.Init();
        for (register int i=1;i<=len;i++) ans.a[i]=a[i]-other.a[i];
        for (register int i=1;i<=len;i++) {
            if (ans.a[i]<0) ans.a[i]+=10,ans.a[i+1]-=1;
        }
        for (register int i=len;i>=1;i--) {
            if (ans.a[i]) {
                ans.len=i;
                return ans;
            }
        }
        ans.len=1;
        return ans;
    }
     
}a,b,c;
 
void equ(BigData &u,BigData &v) {
    u.len=v.len;
    for (register int i=1;i<=u.len;i++)  u.a[i]=v.a[i];
    u.a[u.len+1]=0;
}
 
void Sub(BigData &u,BigData &v) {
    for (register int i=1;i<=u.len;i++) u.a[i]-=v.a[i];
    for (register int i=1;i<=u.len;i++)
        if (u.a[i]<0) u.a[i]+=10,u.a[i+1]-=1;
    for (register int i=u.len;i>=1;i--) {
        if (u.a[i]) {
            u.len=i;
            return;
        }
    }
    u.len=1;
}
 
int main() {
    a.Init(); b.Init();
    a.read(); b.read();
    c=a-b;
    if (c.len==1&&c.a[1]==0) {
        a.write();
        return 0;
    }
    if (b<a) swap(a,b);
    while (a.len>1||a.a[1]) {
        BigData c,d;
        equ(c,a);
        equ(d,c);
        while (c<b) {
            equ(d,c);
            c.Get_Double();
            c.a[c.len+1]=0;
        }
        for (register int i=d.len+1;i<=b.len;i++) d.a[i]=0;
        Sub(b,d);
        if (b<a) swap(a,b);
    }
    b.write();
    return 0;
}

AC代码:

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<time.h>
#include<vector>
#include<cstring>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int N=10000;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const int pw[10]={1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};

char s[10010];
struct BigData {
	int len,a[N];

	void Init() {
		len=0;
		memset(a,0,sizeof(a));
	}
	
	void read() {
		scanf("%s",s+1);
		int l=strlen(s+1);
		for (register int i=l;i>=1;i--) {
			if ((l-i+1)%8==1) len++;
			a[len]+=pw[(l-i)%8]*(s[i]-'0');
		}
	}
	
	template<typename tp> inline void write(tp x) {
		if (x==0) return (void) (putchar('0'));
		if (x<0) putchar('-'),x=-x;
		int pr[20]; register int cnt=0;
		for (;x;x/=10) pr[++cnt]=x%10;
		while (cnt) putchar(pr[cnt--]+'0');
	}
	
	void write() {
		printf("%d",a[len]);
		for (register int i=len-1;i>=1;i--) {
			int pr[20]; register int cnt=0;
			for (;a[i];a[i]/=10) pr[++cnt]=a[i]%10;
			for (int j=1;j<=8-cnt;j++) putchar('0');
			while (cnt) putchar(pr[cnt--]+'0');
		}
	}

	bool operator < (const BigData &other) const {
		if (len<other.len) return 1;
		if (len>other.len) return 0;
		for (register int i=len;i>=1;i--) {
			if (a[i]!=other.a[i])
				return a[i]<other.a[i];
		}
		return 0;
	}

	void Get_Half() {
		int res=0;
		for (int i=len;i>=1;i--) {
			if (res) a[i]+=pw[8];
			res=a[i]&1;
			a[i]>>=1;
		}
		while (!a[len]&&len>1) len--;
	}

	void Get_Double() {
		for (register int i=1;i<=len;i++) a[i]<<=1;
		a[len+1]=a[len+2]=0;
		for (register int i=1;i<=len;i++) {
			if (a[i]>=pw[8]) a[i]-=pw[8],a[i+1]+=1;
		}
		if (a[len+1]) len++;
	}

	inline bool ord() {
		if (a[1]==0&&len==1) return 1;
		return a[1]&1;
	}
	
	BigData operator - (const BigData &other) const {
		BigData ans; ans.Init();
		for (register int i=1;i<=len;i++) ans.a[i]=a[i]-other.a[i];
		for (register int i=1;i<=len;i++) {
			if (ans.a[i]<0) ans.a[i]+=pw[8],ans.a[i+1]-=1;
		}
		for (register int i=len;i>=1;i--) {
			if (ans.a[i]) {
				ans.len=i;
				return ans;
			}
		}
		ans.len=1;
		return ans;
	}
	
}a,b,c;

int main() {
	a.Init(); b.Init();
	a.read(); b.read();
	c=a-b;
	if (c.len==1&&c.a[1]==0) {
		a.write();
		return 0;
	}
	int cnt=0;
	if (b<a) swap(a,b);
	while (a.len>1||a.a[1]) {
		b=b-a;
		while (!a.ord()&&!b.ord()) {
			a.Get_Half(); b.Get_Half();
			cnt++;
		}
		while (!a.ord()) a.Get_Half();
		while (!b.ord()) b.Get_Half();
		if (b<a) swap(a,b);
	}
	for (int i=1;i<=cnt;i++) b.Get_Double();
	b.write();
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值