第十三届蓝桥杯决赛真题-最大公约数(Python组)题解

题目描述

给定一个数组,每次操作可以选择数组中任意两个相邻的元素 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 ≤ 106;

对于所有评测用例,1 ≤ n ≤ 100000 ,1 ≤ ai ≤ 109。‘

PS: 一道蓝桥杯考场上AC的题目,近期重新整理并优化了代码(结合了肖佬和b站蜗神的思路后优化算法),希望有机会跟大家交流探讨,也希望我的方法能帮到需要帮助的人。若有改进意见的小伙伴请评论区留言,感激不尽!

 解题思路:

        分析了一下,数据范围是[1,1e5],数组长度不大,算法可选范围更多了一些,涉及到数组维护什么的,首选就是线段树了,本题有不用线段树的写法,由于笔者写惯了线段树,那么本题我也引用线段树来解决问题。

        有两种不同的情况:

        第一种情况:对于数组中的任意一个下标i,若有ai为1,或者说如果出现m个1(m>=1),那么让长度为n的整个数组最后只含1的最小操作次数就是为n - m。举个例子,设数组A = [1,4,6],那么我们令其数组只剩下1的操作方法为:将1分别与其他两项非1进行gcd,有n - m = 3 - 1 =2,所得2次便是最小操作次数。

       

        第二种情况:当数组中不存在任意两个相邻的数互质的情况(相邻的两数gcd为1)那么我们可以考虑找到一对i,j,找到一个区间(ai,ai+1,....,aj),若此区间能满足gcd = 1,我们便可以在区间上来找到一个i和j(i < j),以j - i来维护最小的m就可了。到此此题解决!考场上我是写一个线段树去维护这个区间gcd,最后做一次滑动窗口便可AC本题了,代码如下:

from math import gcd,inf

m = 0
def build(k,l,r):
    global m
    if l == r:
        tree[k] = a[l]
        if tree[k] == 1:
            m += 1  # 第一种情况
        return
    mid = l + r >> 1
    build(k << 1,l,mid)
    build(k << 1 | 1,mid + 1,r)
    tree[k] = gcd(tree[k << 1],tree[k << 1 | 1])

def queryGCD(k,l,r,x,y):
    if l == x and r == y: return tree[k]
    mid = l + r >> 1
    if y <= mid:     g = queryGCD(k << 1,l, mid,x,y)
    else:
        if x > mid:  g = queryGCD(k << 1 | 1,mid + 1, r ,x,y)
        else:        g = gcd( queryGCD(k << 1,l, mid,x,mid) ,queryGCD(k << 1|1,mid + 1, r,mid + 1,y) )
    return g

def main():
    global tree,a,m
    n = int(input())
    a = [0] + list(map(int,input().split()))
    tree = [0] * (4 * n)
    build(1,1,n)  # 建树
    if m > 0:   print(n - m)
    else:
        m,i = inf,1
        for j in range(1,n+1):
            while i < j and queryGCD(1,1,n,i + 1,j) == 1:   i += 1
            if queryGCD(1,1,n,i,j) == 1:                    m = min(j - i,m)

        print(n + m - 1 if m < n else -1 )

main()

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值