解题思路:
我们需要找最小次数去得到 1,有 1之后顺着就可以把所有数变成 1,可以通过线段树维护区间最大公约数,然后通过二分求解最小次数
注意事项:
参考代码:
import java.util.*;
class Main {
static final int N = 100009;
static int n;
static int[] a = new int[N];
static int[] tr = new int[N << 2];
static void build(int l, int r, int p) {
if (l == r) {
tr[p] = a[l];
return;
}
int mid = l + ((r - l) >> 1);
build(l, mid, p << 1);
build(mid + 1, r, (p << 1) | 1);
tr[p] = gcd(tr[p << 1], tr[(p << 1) | 1]);
}
static int query(int l, int r, int s, int t, int p) {
int ans = 0;
if (l >= s && r <= t) return tr[p];
int mid = l + ((r - l) >> 1);
if (mid >= s) ans = gcd(ans, query(l, mid, s, t, p << 1));
if (mid < t) ans = gcd(ans, query(mid + 1, r, s, t, (p << 1) | 1));
return ans;
}
static int gcd(int a, int b) {
while (b != 0) {
int tmp = a % b;
a = b;
b = tmp;
}
return a;
}
static void solve() {
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
int cnt_one = 0;
for (int i = 1; i <= n; i++) {
a[i] = scanner.nextInt();
if (a[i] == 1) cnt_one++;
}
if (cnt_one != 0) {
System.out.println(n - cnt_one);
return;
}
build(1, n, 1);
int ans = Integer.MAX_VALUE;
for (int i = 1; i <= n; i++) {
int l = i, r = n;
int cnt = Integer.MAX_VALUE;
while (l <= r) {
int mid = l + ((r - l) >> 1);
if (query(1, n, i, mid, 1) == 1) {
cnt = mid - i;
r = mid - 1;
} else {
l = mid + 1;
}
}
ans = Math.min(ans, cnt);
}
if (ans == Integer.MAX_VALUE) {
System.out.println(-1);
return;
}
ans = ans + n - 1;
System.out.println(ans);
}
public static void main(String[] args) {
solve();
}
}
0.0分
1 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复