第十三届蓝桥杯Java、C++、Python组国赛真题——最大公约数(三语言AC)

2年前Python源码8079
第十三届蓝桥杯Java、C++、Python组国赛真题——最大公约数(三语言AC) 执 梗 已于2022-10-18 18:08:47修改 792 收藏 9 分类专栏: 蓝桥真题 文章标签: 蓝桥杯 java c++ 算法 python 于2022-10-18 18:07:59首次发布 蓝桥真题 专栏收录该内容 17 篇文章 154 订阅 订阅专栏

目录 1.最大公约数1.问题描述2.输入格式2.输出格式3.样例输入4.样例输出5.数据范围6.原题连接 2.解题思路3.Ac_codeC++JavaPthon

1.最大公约数 1.问题描述

给定一个数组, 每次操作可以选择数组中任意两个相邻的元素 x , y x, y x,y 并将其 中的一个元素替换为 gcd ⁡ ( x , y ) \operatorname{gcd}(x, y) gcd(x,y), 其中 gcd ⁡ ( x , y ) \operatorname{gcd}(x, y) gcd(x,y) 表示 x x x 和 y y y 的最大公约数。 请问最少需要多少次操作才能让整个数组只含 1 。

2.输入格式

输入的第一行包含一个整数 nn, 表示数组长度。

第二行包含 n n n 个整数 a 1 , a 2 , ⋯   , a n a_{1}, a_{2}, \cdots, a_{n} a1​,a2​,⋯,an​ 相邻两个整数之间用一个空格分隔。

2.输出格式

输出一行包含一个整数, 表示最少操作次数。如果无论怎么操作都无法满 足要求, 输出 − 1 −1 −1 。

3.样例输入

3

4 6 9

4.样例输出

4

5.数据范围

1 ≤ n ≤ 100000 , 1 ≤ a i ≤ 1 0 9 1≤n≤100000,1≤a i ≤10^9 1≤n≤100000,1≤ai≤109

6.原题连接

最大公约数

2.解题思路

首先先考虑数组中是否存在 1 1 1,如果数组中存在 1 1 1,那么我们可以直接进行平铺把全部变成 1 1 1,假设 1 1 1的个数为 x x x个,那么最终的答案应该是 n − x n-x n−x次。

如果原数组中不存在 1 1 1,该如何呢?那么我们应该想方法变出一个 1 1 1,然后使用这个 1 1 1进行平推将数组全部变成 1 1 1。关于 g c d gcd gcd,我们首先要明白——如果一段子数组的的 g c d gcd gcd为 1 1 1,那么原数组的 g c d gcd gcd也一定为 1 1 1。 这也非常容易理解,如果存在一个数组的 g c d gcd gcd为 1 1 1,那么这个数组无论再加上任何正整数, g c d gcd gcd也永远是 1 1 1,因为 1 1 1和任何数的 g c d gcd gcd都是 1 1 1。

题意要求最少次数,那么在没有 1 1 1的情况下,我们需要使用最少的步数获得 1 1 1,那么就是我们需要在数组中找到最短的子数组,使得它们的 g c d gcd gcd为1。所以我们会涉及道查询区间 g c d gcd gcd这个操作,直接暴力肯定不可取,所以我们应该联想到线段树来进行查询。

那么如何寻找最短的子数组满足区间 g c d gcd gcd为 1 1 1呢?我们可以考虑二分。对于数组中的每个数我们都可以固定为左端点 l l l,然后去二分它的右端点,求出使得 区间 [ l , r ] 区间[l,r] 区间[l,r]的 g c d gcd gcd为 1 1 1的最小的右端点。既然二分就需要满足二段性,根据上一段的描述,我们可以知道,如果 [ l , r ] [l,r] [l,r]的 g c d gcd gcd 为 1 1 1,那么 [ l , r + 1 ] . . . [ l , n ] [l,r+1]...[l,n] [l,r+1]...[l,n]这些区间的 g c d gcd gcd也一定为 1 1 1, 而 [ l , l + 1 ] . . . [ l , r − 1 ] [l,l+1]...[l,r-1] [l,l+1]...[l,r−1]这些区间却并不一定符合条件。这样每个数我们都定为左端点去二分它的右端点,所有答案取最小值就能找出 g c d gcd gcd位 1 1 1的最短区间。

当然我们如何判断无解的情况呢?还是根据上述 g c d gcd gcd的理论知识,如果 [ 1 , n ] [1,n] [1,n]的 g c d gcd gcd都不为 1 1 1,那么任何子数组的 g c d gcd gcd也不可能为 1 1 1,此时为无解。

注意:Python语言运行较慢,推荐写成st表,不推荐写线段树,线段树常数太大。 时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)。

3.Ac_code C++ #include<bits/stdc++.h> using namespace std; typedef long long LL; const int inf = 0x3f3f3f3f; const int mod = 1000000007; const int N=100010; int n; int a[N]; struct node { int l, r; int g; }tr[N * 4]; void pushup(int u) { tr[u].g =__gcd(tr[u<<1].g,tr[u<<1|1].g); } void build(int u, int l, int r) { if (l == r) tr[u] = {l, r, a[r]}; else { tr[u] = {l, r}; int mid = l + r >> 1; build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r); pushup(u); } } int query(int u, int l, int r) { if (tr[u].l >= l && tr[u].r <= r) return tr[u].g; int mid = tr[u].l + tr[u].r >> 1; if(r<=mid) return query(u<<1,l,r); else if(l>mid) return query(u<<1|1,l,r); else return __gcd(query(u<<1,l,r),query(u<<1|1,l,r)); } void solve() { cin>>n; int f=0; for(int i=1;i<=n;++i){ cin>>a[i]; if(a[i]==1) f++; } if(f){ printf("%d\n",n-f); return; } build(1,1,n); if(query(1,1,n)!=1){ puts("-1"); return; } int ans=inf; for(int i=1;i<=n;++i){ int l=i+1,r=n+1; while(l<r){ int mid=l+r>>1; if(query(1,i,mid)==1) r=mid; else l=mid+1; } if(query(1,i,r)==1) ans=min(ans,r-i); } printf("%d\n",n-1+ans); } int main() { solve(); return 0; } Java import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.Scanner; public class Main { static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out)); static int N = 100010; static Node[] tr = new Node[N * 4]; static int[] a = new int[N]; public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int f = 0; for (int i = 1; i <= n; ++i) { a[i] = sc.nextInt(); if (a[i] == 1) f++; } if (f != 0) { out.println(n - f); out.flush(); return; } build(1, 1, n); if (query(1, 1, n) != 1) { out.println(-1); out.flush(); return; } int ans = 0x3f3f3f3f; for (int i = 1; i <= n; ++i) { int l = i + 1, r = n + 1; while (l < r) { int mid = l + r >> 1; if (query(1, i, mid) == 1) r = mid; else l = mid + 1; } if (query(1, i, r) == 1) ans = Math.min(ans, r - i); } out.println(n - 1 + ans); out.flush(); } static int gcd(int a,int b){ return b == 0 ? a:gcd(b,a%b); } static void pushup(int u) { tr[u].g = gcd(tr[u << 1].g, tr[u << 1 | 1].g); } static void build(int u, int l, int r) { if (l == r) tr[u] = new Node(l, r, a[r]); else { tr[u] = new Node(l, r, 0); int mid = l + r >> 1; build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r); pushup(u); } } static int query(int u, int l, int r) { if (tr[u].l >= l && tr[u].r <= r) return tr[u].g; int mid = tr[u].l + tr[u].r >> 1; if (r <= mid) return query(u << 1, l, r); else if (l > mid) return query(u << 1 | 1, l, r); else return gcd(query(u << 1, l, r), query(u << 1 | 1, l, r)); } static class Node { int l, r, g; public Node(int l, int r, int g) { this.l = l; this.r = r; this.g = g; } } } Pthon from math import gcd import math def rmq_init(arr): arr_len = len(arr) exp = int(math.log(arr_len, 2)) dp = [[0] * (exp + 1) for _ in range(arr_len + 1)] for i, a in enumerate(arr): dp[i + 1][0] = a for j in range(1, exp + 1): for start in range(1, arr_len + 1): if start + (1 << j) - 1 > arr_len: break dp[start][j] = gcd(dp[start][j - 1], dp[start + (1 << (j - 1))][j - 1]) return dp def rmq_ask(dp, left, right): k = int(math.log(right - left + 1, 2)) return gcd(dp[left][k], dp[right + 1 - (1 << k)][k]) n = int(input()) a = list(map(int, input().split())) cnt1 = sum(ai == 1 for ai in a) if cnt1 > 0: print(n - cnt1) else: dp = rmq_init(a) if rmq_ask(dp, 1, n) != 1: print(-1) else: ans = 10 ** 9 for i in range(1, n): l, r = i, n while l < r: mid = (l + r) >> 1 if rmq_ask(dp, i, mid) == 1: r = mid else: l = mid + 1 if rmq_ask(dp, i, r) == 1: ans = min(ans, r-i) print(ans + n-1)

相关文章

云原生DevOps篇:使用Pipeline流水线将know-system项目自动化发版到Kubernetes集群

云原生DevOps篇:使用Pipeline流水线将know-system项目自动化发版到Kubernetes集群...

机器学习进阶之 时域/时间卷积网络 TCN 概念+由来+原理+代码实现

机器学习进阶之 时域/时间卷积网络 TCN 概念+由来+原理+代码实现...

MATLAB Appdesigner开发独立桌面App全流程(一):以打开串口功能为例介绍Appdesigner的基本使用

MATLAB Appdesigner开发独立桌面App全流程(一):以打开串口功能为例介绍Appdesigner的基本使用...

2022MySQL 8.0.30 安装及配置(详细教程)

2022MySQL 8.0.30 安装及配置(详细教程)...

【C++修炼之路】6. 内存管理

【C++修炼之路】6. 内存管理...

TCP通信过程三次握手、TCP通信四次挥手

TCP通信过程三次握手、TCP通信四次挥手...