解题思路:见注释
注意事项:
参考代码:
#include<bits/stdc++.h>
//当数组中已经存在1时,设1的数量为numof1,显然每更新一次可以让一个不为1的数变为1,且最多可以让一个不为1的数变为1,所以最少要更新n-numof1次;
//当数组中不存在1时,如果所有元素的最大公因数不为1,显然永远不可能将任一个元素变为1,输出-1。
// 否则,寻找长度最短的区间[l,r](长度记为len),这个区间的最大公因数为1,那么使这个区间出现1需要len-1次,也就是先把a[l+1]变为
//gcd(a[l],a[l+1]),再把a[l+2]变为gcd(a[l+1],a[l+2])...最后把a[r]变为gcd(a[r-1],a[r]),显然最终a[r]就是1,共操作len-1次,再用这个1更新整个数组,共操作n-1次,
//所以一共操作len-1+n-1次。用二分寻找len,用线段树维护区间最大公因数。
using namespace std;
#define maxn 100010
int n;
int a[maxn];
struct node{
int l;
int r;
int gcdval;//a[l]到a[r]这些数的最大公约数
}tree[maxn<<2];
int gcd(int x,int y){
while(y){
x=x%y;
if(x==0)break;
y=y%x;
}
return max(x,y);
}
void build(int idx,int l,int r){
tree[idx].l=l;tree[idx].r=r;
if(l==r){
tree[idx].gcdval=a[l];
}
else{
int mid=(l+r)>>1;
build(idx<<1,l,mid);
build(idx<<1|1,mid+1,r);
tree[idx].gcdval=gcd(tree[idx<<1].gcdval,tree[idx<<1|1].gcdval);
}
}
int search(int idx,int l,int r){
if(l<=tree[idx].l&&tree[idx].r<=r){
return tree[idx].gcdval;
}
//if(r<tree[idx].l||l>tree[idx].r)return 0;//这句话事实上不会运行到
int gcdval1=0,gcdval2=0;
if(tree[idx<<1].r>=l){
gcdval1=search(idx<<1,l,r);
}
if(tree[idx<<1|1].l<=r){
gcdval2=search(idx<<1|1,l,r);
}
if(gcdval1==0||gcdval2==0)return max(gcdval1,gcdval2);
return gcd(gcdval1,gcdval2);
}
bool check(int len){
for(int i=1;i<=n-len+1;i++){
if(search(1,i,i+len-1)==1)return true;
}
return false;
}
int main(){
scanf("%d",&n);
int numof1=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(a[i]==1)numof1++;
}
if(numof1){
printf("%d",n-numof1);return 0;
}
build(1,1,n);
if(check(n)==false){
printf("-1");return 0;
}
int l=1,r=n;
while(l<r){
int mid=(l+r)>>1;
if(check(mid))r=mid;
else l=mid+1;
}
printf("%d",l-1+n-1);
return 0;
}
0.0分
2 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复