前话
数论就是研究整数的理论。包括公约公倍数、质数、欧拉定理和同余方程等。
正文
其实数论不止那么简单
正文
第一题:SuperGCD
这一题就是很烦的代码加很烦的思路。
GCD大家都想起了辗转相除法(gcd(a,b)=gcd(b,a%b));
因为数据很大而且除运算和mod运算可能很浪费时间。所以推广辗转相减法:
当两个数都为偶数时,gcd(a,b)=gcd(a/2,b/2)*2;
当其中一个为偶数且另外一个不为偶数时,gcd(a,b)=gcd(a/2,b) (a mod 2 == 0)
gcd(a,b)=gcd(a,b/2) (b mod 2 == 0)
否则,gcd(a,b)=gcd(b,a-b);
没错,万恶的代码。(迭代万岁,递归超时哦!)
代码<deal>
#include<cstdio>
#include<cstdlib>
#include<cstring>
char s1[10010],s2[10010];
struct node{
int s[10010];
int l;
friend node operator-(node a,const node&b){
node t;
t.l=a.l;
for(int i=1;i<=t.l;i++){
if(a.s[i]<b.s[i]){
a.s[i]+=10;
a.s[i+1]-=1;
}
t.s[i]=a.s[i]-b.s[i];
}
while(t.s[t.l]==0) t.l--;
return t;
}
int compare(const node &b)const{
if(l<b.l) return 0;
if(l>b.l) return 1;
for(int i=l;i>=1;i--){
if(s[i]>b.s[i]) return 1;
if(s[i]<b.s[i]) return 0;
}
return 1e9;
}
friend node operator/(const node&a,const int&x){
int now=0;
node t=a;
for(int i=t.l;i>=1;i--){
now*=10;
now+=t.s[i];
t.s[i]=now/x;
now%=x;
}
while(t.s[t.l]==0) t.l--;
return t;
}
friend node operator*(const node&a,const int&x){
node t;
t=a;
t.s[t.l+1]=0;
for(int i=1;i<=t.l;i++)
t.s[i]*=x;
for(int i=1;i<=t.l;i++){
if(t.s[i]>9){
t.s[i+1]+=t.s[i]/10;
t.s[i]%=10;
if(i==t.l) t.l++;
}
}
return t;
}
};
node a,b;
int main(){
scanf("%s %s",s1,s2);
a.l=strlen(s1),b.l=strlen(s2);
for(int i=0;i<a.l;i++)
a.s[a.l-i]=s1[i]-'0';
for(int i=0;i<b.l;i++)
b.s[b.l-i]=s2[i]-'0';
int t=0;
while(a.s[1]%2==0 && b.s[1]%2==0) {
t++;
a=a/2;
b=b/2;
}
while(a.compare(b)!=1e9){
if(a.compare(b)==1) a=a-b;else b=b-a;
while(a.s[1]%2==0) a=a/2;
while(b.s[1]%2==0) b=b/2;
}
for(int i=1;i<=t;i++)
a=a*2;
for(int i=a.l;i>=1;i--)
printf("%d",a.s[i]);
}