P8792 [蓝桥杯 2022 国 A] 最大公约数 题解
gesong1234 · · 题解
题目传送门:P8792 [蓝桥杯 2022 国 A] 最大公约数。
思路
其实,这道题就是枚举,只需要枚举从哪个端点开始,如果合成了
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,a[1234567],cnt;
main(){
cin>>n;
for (int i=1;i<=n;i++) cin>>a[i],cnt+=(a[i]==1?1:0);
if (cnt){//特判,如果有1了,就不用枚举了。
cout <<n-cnt;
return 0;
}
int ans=1e9;
for (int i=1;i<n;i++){//枚举开始端点
int x=a[i],sum=0;
for (int j=i+1;j<=n;j++){
sum++;
x=__gcd(x,a[j]);
if (x==1){//成功了
ans=min(ans,sum);
break;
}
}
}
if (ans==1e9) cout <<-1;//不合法
else cout <<n+ans-1;
return 0;
}
结果TLE了,我们要想想优化。
优化
我们发现,在枚举的时候,一直用
#include<bits/stdc++.h>
#define int long long
#define lc 2*k
#define rc 2*k+1
using namespace std;
int n,a[1234567],cnt;
struct nord{
int l,r,mx;
}t[1234567];
void build(int k,int l,int r){//建树
t[k].l=l,t[k].r=r;
if (l==r){
t[k].mx=a[l];
return ;
}
int mid=(l+r)/2;
build(lc,l,mid);
build(rc,mid+1,r);
t[k].mx=__gcd(t[lc].mx,t[rc].mx);
}
int ask(int k,int l,int r){//求区间gcd
if (l<=t[k].l&&r>=t[k].r) return t[k].mx;
int ans=0;
int mid=(t[k].l+t[k].r)/2;
if (l<=mid) ans=__gcd(ans,ask(lc,l,r));
if (r>mid) ans=__gcd(ans,ask(rc,l,r));
return ans;
}
main(){
cin>>n;
for (int i=1;i<=n;i++) cin>>a[i],cnt+=(a[i]==1?1:0);
build(1,1,n);
if (cnt){//特殊情况
cout <<n-cnt;
return 0;
}
int ans=1e9;
int i=1;
for (int j=1;j<=n;j++){//枚举
while (i<j&&ask(1,i+1,j)==1) i++;//一直往前走
if (ask(1,i,j)==1) ans=min(ans,j-i);//成功了
}
if (ans==1e9) cout <<-1;//不合法
else cout <<n+ans-1;
return 0;
}