蓝桥杯-数的拆分

本文综合官网其他用户题解及代码,加入自身理解。先分析符合题目要求的几种情况,依据唯一分解定理探讨数的形式;接着说明检查数是否符合形式的方法,还对形式4分类讨论以缩小问题规模;最后给出AC代码,并提及Python代码素数分解时除法使用的注意点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文综合了上面的官网里的其他用户的题解及代码,并加入自己的理解

1. 题解

1.1 分析有几种情况符合题目要求

由唯一分解定理,任何大于1的整数a都可以分解为它的质因数的乘积

a={p_{1}}^{k_{1}}\cdot {p_{2}}^{k_{2}}\cdot ...其中p_i是a_i的质因数,k_i是大于等于1的整数

a=x_{1}^{y_{1}}\cdot x_{2}^{y_{2}}有如下几种形式:(形式1)a=x_{1}^{2}\cdot 1;(形式2)a=x^3\cdot 1;(形式3)a=x_{1}^2\cdot x_{2}^2(显然可以归到a=x_{1}^{2}\cdot 1的形式);(形式4)a=x_{1}^2\cdot x_{2}^3(就是将唯一分解中,指数为偶数的部分化为p_{1}^{2k}=(p_{1}^{k})^2放入x_{1}那一堆,指数为奇数的部分化为p_2^{2k+1}=p_2^3\cdot p_2^{2k-1}分别放x_2那堆和x_1那堆)


1.2 如何检查一个数a是否符合上面的任一形式

观察形式1,2,4,可知,只要a唯一分解后得到的质因数的指数大于或等于2,这个质因数就能对应到某种形式;只要所有质因数都能对应到某种形式,a就是符合要求的。

一般的唯一分解算法需要求n以内的素数,复杂度O(\sqrt{n}),复杂度高达10^9,超时

逐一分析上面的每种形式。

形式1:特判\sqrt{a}是否为整数

形式2:特判\sqrt[3]{a}是否为整数

形式4:?

1.3 形式4

考虑a=x_0^2\cdot x_0^3,以x_0为分界点,分类讨论

case 1:a=x_1^2\cdot y_1^3 ,\;\; \; \; \; \; y_1<x_0<x_1

case 2:a=x_2^2\cdot y_2^2,\; \; \; \; \; \; x_2<x_0<y_2

则case 1可以转化为a=(x_1'^2\cdot y_1^3)\cdot x_1''^2=a'\cdot x_1''^2,\; \; \; \; \; \; x_1',y_1<x_0

case 2可以转为a=(x_2^2\cdot y_2'^3)\cdot y_2''^3=a'\cdot y_2''^3,\; \; \; \; \; \; x_2,y_2'<x_0

a'相当于缩小了问题规模,因为它的x_iy_i都小于x_0,要检查它是否符合我们之前提到的形式4,作唯一分解,只需要x_0以内的素数(因为我们限定了x_iy_i的大小!),复杂度O(\sqrt{x_0}),令a=x_0^2\cdot x_0^3=x_0^5=10^{18}x_0约为4000,O(\sqrt{x_0})约为64,配合T的上界10^5,刚好在10^7!

至于case 1、2括号后面的部分,因为不知道x_i''y_i''的大小是否落在x_0内,可能唯一分解不到。我们对a做完x_0以内的素数唯一分解后,若a剩余的部分大于1,说明x_i''y_i''落在x_0外,那我们就需要额外判断a剩余部分开二次根号(对应x_i'')或开立方根(对应y_i'')是否为整数。

2. AC代码

顺便说一句,python代码作素数唯一分解的时候,除法必须用“//”而不是“/”,不然答案是错的。我想破脑袋也不明白为什么,如有读者知道,麻烦在评论留下你的见解。

# 参考蓝桥杯官网题解“python战狼”的代码,感谢
MAXN=4000
primes=[]
# 欧拉筛O(n)
def pre():
    global primes,MAXN
    not_prime = [False for _ in range(MAXN)]
    for i in range(2,MAXN):
        if not not_prime[i]:
            primes.append(i)
        for p in primes:
            if i*p>=MAXN:
                break
            not_prime[i * p] = True
            if i%p==0:
                '''
                i是p的倍数,之前已被p筛过;又素数表中素数从小到大
                排列,此后i*p'必为p的倍数,此后仍会被p筛一次,不需要
                在这里先筛一次
                '''
                break


def is_square(x):
    temp = int(x**(1 / 2))
    return temp ** 2 == x or (temp + 1) ** 2 ==x # 小心误差!

def is_cubic(x):
    temp = int(x**(1 / 3))
    return temp ** 3 == x or (temp + 1) ** 3 == x # 小心误差!

def judge(a):
    global primes
    if a == 1:
        return False

    # a是否为某个数的平方
    if is_square(a):
        return True

    # a是否为某个数的3次方
    if is_cubic(a):
        return True

    # a是否为某个数的4次方
    # 已包括在平方的判断内

    # a是否为(x1^2)*(x2^3)的形式
    for p in primes:
        if a < p:
            break
        cnt = 0
        while a % p == 0:
            a //= p  # 为什么用/就会错啊啊啊!!!!!!!!!!!!!!!!!!
            cnt += 1
        if cnt == 1:
            return False
    if a != 1:
        if not is_square(a) and not is_cubic(a):
            return False
    return True


t=int(input())
pre()
for i in range(t):
    a=int(input())
    if judge(a):
        print("yes")
    else:
        print("no")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值