题解:
今天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;
}