为什么NKOJ的题交JAVA会被keyword卡System,还不能用python水高精度……
题目分析
回归正题,由于本题数据范围 0 ≤ A , B ≤ 1 0 10000 0 \le A,B \le 10^{10000} 0≤A,B≤1010000两个 10000 10000 10000位的整数算GCD,所以用高精度欧几里得GCD的话会使得算法时间复杂度不够优秀(虽然各位Dalao都会卡常过题,但本蒟蒻还是希望给大家带来较好的算法)
这里为了可以更有惊无险的AC本题,我采用了辗转相除Pro优化法,其内容如下:(可能是环境不一样,在另外一边看起来很好看,粘过来难看死了)
g
c
d
(
a
,
b
)
=
{
a
[
a
=
b
]
g
c
d
(
b
,
a
)
[
a
<
b
]
g
c
d
(
a
,
b
2
)
[
a
奇数
b
偶数
]
g
c
d
(
a
2
,
b
)
[
a
偶数
b
奇数
]
g
c
d
(
a
2
,
b
2
)
×
2
[
a
,
b
均为偶数
]
g
c
d
(
a
−
b
,
b
)
;
[
a
,
b
均为奇数
]
\mathrm{gcd}(a,b)= \left\{\begin{matrix} a \ \ \ [a=b]\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\ \mathrm{gcd}(b,a)\ \ \ [a<b]\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\ \mathrm{gcd}(a,\frac{b}{2})\ \ \ [a奇数b偶数]\ \ \ \ \ \ \ \ \ \ \ \\ \mathrm{gcd}(\frac{a}{2},b)\ \ \ [a偶数b奇数]\ \ \ \ \ \ \ \ \ \ \ \\ \mathrm{gcd}(\frac{a}{2},\frac{b}{2}) \times 2\ \ \ [a,b均为偶数]\ \ \ \\ \mathrm{gcd}(a-b,b);\ \ \ [a,b均为奇数]\ \ \ \ \end{matrix}\right.
gcd(a,b)=⎩
⎨
⎧a [a=b] gcd(b,a) [a<b] gcd(a,2b) [a奇数b偶数] gcd(2a,b) [a偶数b奇数] gcd(2a,2b)×2 [a,b均为偶数] gcd(a−b,b); [a,b均为奇数]
但是很明显,我们的代码并不能用函数实现,这样就会MLE掉(函数递归的本质是压栈,当调用次数过多栈会原地爆炸),所以我们需要把这个转化为循环,在循环中又两个变量(高精度数)a
,b
,分别记录当前的两个数a
,b
,当找到a==b
时,就直接break
输出a
的值;
注意,本体难点在于实现:高精需压位,输出需补0,若是忘了写,WA两行泪;(我的WA40pts就是没有补0造成的,TLE70pts就是用了递归+没有压位)
听着是不是很简单,当你实现的时候就知道什么叫坐牢了
注意以下代码不知道为什么只过得了NKOJ的测试点,LUOGU和POJ的OIER们请移步其他文章或自己尝试去写;
AC-NKOJ Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
vector<int> a,b;
int kkk=1;
int cmp(vector<int> x,vector<int> y){
if(x.size()!=y.size()){
if(x.size()>y.size()){return 1;}
else{return 0;}
}
for(int i=x.size()-1;i>=0;i--){
if(x[i]!=y[i]){
if(x[i]>y[i]){return 1;}
else{return 0;}
}
}
return 3;
}
vector<int> sub(vector<int> a,vector<int> b){
int k=0;
vector<int> c;
for(int i=0;i<a.size();i++){
k+=a[i];
if(i<b.size()){
k-=b[i];
}
c.push_back((k+100000000)%100000000);
if(k<0){
k=-1;
}else{
k=0;
}
}
while(c.size() > 1 && c.back()==0){
c.pop_back();
}
return c;
}
vector<int> div(vector<int> a,int b){
int k=0;
vector<int> c;
for(int i=a.size()-1;i>=0;i--){
k=k*100000000+a[i];
c.push_back(k/b);
k%=b;
}
reverse(c.begin(),c.end());
while(c.size()>1&&c.back()==0){
c.pop_back();
}
return c;
}
vector<int> mul(vector<int> a , int b){
int t=0;
vector<int> c;
for(int i=0;i<a.size();i++){
t+=a[i]*b;
c.push_back(t%100000000);
t/=100000000;
}
while(t){
c.push_back(t%100000000);
t/=100000000;
}
while(c.size()>1&&c.back()==0){
c.pop_back();
}
return c;
}
signed main(){
string ch1,ch2;
cin>>ch1>>ch2;
int j=0,sum=0,t=1;
for(int i=ch1.size()-1;i>=0;i--){
j++;
sum=sum+t*(ch1[i]-'0');
t*=10;
if(j==8||i==0){
a.push_back(sum);
j=0;
t=1;
sum=0;
}
}
j=0,sum=0,t=1;
for(int i=ch2.size()-1;i>=0;i--){
j++;
sum=sum+t*(ch2[i]-'0');
t*=10;
if(j==8||i==0){
b.push_back(sum);
j=0;
sum=0;
t=1;
}
}
while(1){
int k=cmp(a,b);
// for(int i=a.size()-1;i>=0;i--){printf("%lld",a[i]);}
// printf("\n");
// for(int i=b.size()-1;i>=0;i--){printf("%lld",b[i]);}A
// printf("\nssss\n");
// Debug
if(!k){a.swap(b);}
if(k==3){
a=mul(a,kkk);
printf("%lld",a[a.size()-1]);
if(a.size()>1){
for(int i=a.size()-2;i>=0;i--){printf("%08lld",a[i]);}
}
return 0;
}
int numa=a[0]%2;
int numb=b[0]%2;
vector<int> m,n;
if(numa){
if(numb){
m=sub(a,b);
n=b;
}else{
m=a;
n=div(b,2);
}
}else{
if(numb){
m=div(a,2);
n=b;
}else{
m=div(a,2);
n=div(b,2);
kkk*=2;
}
}
a=m;b=n;
}
return 0;
}
【还望各位dalao给蒟蒻一个赞】