您现在的位置是:首页 >其他 >蓝桥杯2022年第十三届决赛真题-最大公约数(C/C++/Java组)网站首页其他
蓝桥杯2022年第十三届决赛真题-最大公约数(C/C++/Java组)
题目描述
给定一个数组,每次操作可以选择数组中任意两个相邻的元素 x, y 并将其中的一个元素替换为 gcd(x, y) ,其中 gcd(x, y) 表示 x 和 y 的最大公约数。
请问最少需要多少次操作才能让整个数组只含 1 。
输入格式
输入的第一行包含一个整数 n ,表示数组长度。
第二行包含 n 个整数 a1, a2, · · · , an,相邻两个整数之间用一个空格分隔。
输出格式
输出一行包含一个整数,表示最少操作次数。如果无论怎么操作都无法满足要求,输出 −1 。
样例输入
3
4 6 9
样例输出
4
提示
对于 30% 的评测用例,n ≤ 500 ,ai ≤ 1000;
对于 50% 的评测用例,n ≤ 5000 ,ai ≤ 1 0 6 10^6 106;
对于所有评测用例,1 ≤ n ≤ 100000 ,1 ≤ ai ≤ 1 0 9 10^9 109。
思路 or 题解
性质 or 结论: g c d ( 1 , x ) = 1 gcd(1, x) = 1 gcd(1,x)=1
我们需要找最小次数去得到
1
1
1
有
1
1
1 之后顺着就可以把所有数变成
1
1
1
我们可以通过线段树 维护区间 GCD
然后通过二分求解最小次数
AC 代码:
/*
Make it simple and keep self stupid
author:Joanh_Lan
*/
#pragma GCC optimize(3)
#pragma GCC optimize("inline") // 如果比赛允许开编译器优化的话,可以默写这两段
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <numeric>
#include <cstring>
#include <cmath>
#include <map>
#include <unordered_map>
#include <bitset>
#include <set>
#include <random>
#include <ctime>
#include <queue>
#include <stack>
#include <climits>
#define buff
ios::sync_with_stdio(false);
cin.tie(0);
// #define int long long
#define ll long long
#define PII pair<int, int>
#define px first
#define py second
typedef std::mt19937 Random_mt19937;
Random_mt19937 rnd(time(0));
using namespace std;
const int mod = 1e9 + 7;
const int inf = 2147483647;
const int N = 100009;
//int Mod(int a,int mod){return (a%mod+mod)%mod;}
//int lowbit(int x){return x&-x;}//最低位1及其后面的0构成的数值
//int qmi(int a, int k, int p){int res = 1 % p;while (k){if (k & 1) res = Mod(res * a , p);a = Mod(a * a , p);k >>= 1;}return res;}
//int inv(int a,int mod){return qmi(a,mod-2,mod);}
//int lcm(int a,int b){return a*b/__gcd(a,b);}
int n, a[N], tr[N << 2];
void bulid(int l, int r, int p)
{
if (l == r)
{
tr[p] = a[l];
return;
}
int mid = l + (r - l >> 1);
bulid(l, mid, p << 1);
bulid(mid + 1, r, p << 1 | 1);
tr[p] = __gcd(tr[p << 1], tr[p << 1 | 1]);
}
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;
}
void solve()
{
cin >> n;
int cnt_one = 0;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
if (a[i] == 1) cnt_one++;
}
if (cnt_one)
{
cout << n - cnt_one << '
';
return;
}
bulid(1, n, 1);
int ans = inf;
for (int i = 1; i <= n; i++)
{
int l = i, r = n;
int cnt = inf;
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 = min(ans, cnt);
}
// cout << ans << '
';
if (ans == inf)
{
cout << -1 << '
';
return;
}
ans = ans + n - 1;
cout << ans << '
';
}
int main()
{
buff;
int _ = 1;
// cin >> _;
while (_--)
solve();
}