0%

【蓝桥杯 2022 国 A】 最大公约数

传送门

Solution

首先考虑数组内已经有 11 的情况。设此时有 n1n_111,则答案为 nn1n-n_1

再考虑数组内没有 11 的情况。要想让整个数组变成 11,首先要先在某一段连续的区间内进行 gcd\gcd 操作,生成第一个 11。然后通过 n1n-1gcd\gcd,把数组的其余元素变成 11。设生成第一个 11 的连续区间长度为 lenlen,本题答案即为

(len1)+(n1)(len - 1) + (n - 1)

注意到每次操作只能改变一个元素的值,所以这个答案的正确性是显然的。

问题转化为如何找到能生成第一个 11,即区间的 gcd\gcd11 的最短区间。如果用朴素的枚举,复杂度为 Θ(n2)\Theta(n^2)。这里考虑用二分答案 + 线段树优化。线段树 O(logn)O(\log n) 查询区间的 gcd\gcd。注意到左端点确定时,区间的 gcd\gcd 随右端点的增大而递减。因此枚举区间的左端点,二分答案找出符合要求的最小右端点即可。

复杂度 Θ(nlogn)\Theta(n\log n)

code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <bits/stdc++.h>
#define N 100010
#define ls k<<1
#define rs k<<1|1
using namespace std;
typedef long long ll;

template <typename T> inline void read(T &x)
{
x = 0; T f = 1; char ch = getchar();
while (!isdigit(ch)) {if (ch == '-') f = -f; ch = getchar();}
while (isdigit(ch)) {x = x * 10 + ch - 48; ch = getchar();}
x *= f;
}

int n, a[N], ans = 1e9, cnt;
struct Tree {
int l, r, val;
} T[N << 2];

void build(int k, int l, int r)
{
T[k].l = l; T[k].r = r;
if (l == r) {
T[k].val = a[l];
return;
}
int mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
T[k].val = __gcd(T[ls].val, T[rs].val);
}

int query(int k, int x, int y)
{
if (x <= T[k].l && T[k].r <= y)
return T[k].val;
int mid = T[k].l + T[k].r >> 1, resl = 0, resr = 0;
if (x <= mid) resl = query(ls, x, y);
if (mid < y) resr = query(rs, x, y);
return __gcd(resl, resr);
}

int main()
{
freopen("a.txt", "r", stdin);
read(n);
for (int i = 1; i <= n; i++) {
read(a[i]);
cnt += (a[i] == 1);
}
if (cnt) {
printf("%d", n - cnt);
return 0;
}
build(1, 1, n);
for (int i = 1; i <= n; i++) {
int le = i, ri = n, mid, res = n + 1;
while (le <= ri) {
mid = le + ri >> 1;
if (query(1, i, mid) == 1) {
res = mid;
ri = mid - 1;
} else le = mid + 1;
}
if (res != n + 1)
ans = min(ans, res - i + n - 1);
}
if (ans == 1e9) printf("-1");
else printf("%d", ans);
return 0;
}