数的拆分

以下为个人对赛题的一个分析,不能保证正确性,如果认为分析有问题,请批评指正。

最终代码有还有问题,为开根号的精度问题,如果是开3,7次根等,则可能误判。

问题描述



问题分析

分析一

问题正整数aia_iai​能否表示为x1y1∗x2y2x_1^{y_1}*x_2^{y_2}x1y1​​∗x2y2​​,一个朴素的想法是获取到 10910^{9}109 次方的素数表,然后用a去模素数表(prime_table)中的元素,当余数为零时y1加1,a=a//prime_table[i]a = a// prime\_table[i]a=a//prime_table[i] 直到余数不为零,即算出了x1,y1x_1,y_1x1​,y1​同理算出x2,y2x_2,y_2x2​,y2​。即

# 获取素数表,为确定性算法。从小到大。
def get_prime_table(n):prime_table = [2, 3, 5, 7]if n <= 10:return prime_tablesqrt_n = math.floor(math.sqrt(n)) + 1for i in range(11, n + 1, 2):j = 0len_prime_table = len(prime_table)flag = Truewhile j < len_prime_table and prime_table[j] < sqrt_n:if i % prime_table[j] == 0:flag = Falsebreakj += 1if flag:prime_table.append(i)return prime_table
# n为题目中的a,prime_table为按序排列的素数表
def can_frac(n, prime_table):prime_len = len(prime_table)  # 素数表元素个数。n_sqrt = math.floor(math.sqrt(n)) + 1  # 根号n范围内有无数的平方满足条件。i = 0# 遍历素数表while i < prime_len and prime_table[i] <= n_sqrt:x1 = ny1 = 0# 算出x1^{y1}while x1 % prime_table[i] == 0:x1 = x1 // prime_table[i]y1 += 1if y1 == 1: return False  # 如果y1等于1不满足题意if x1 == 1:  # 如果刚好为a=x1^{y1}次方的情况。print(prime_table[i], y1)return True# 此时 x1 为 a//x1^{y1}。# 判断第二个数是否满足题意i += 1  # i+1之前不可能有满足的数可以整除x1了if y1 >= 2:y1 = 0while x1 % prime_table[i] == 0:x1 = x1 // prime_table[i]y1 += 1# 如果第二个数为满足题意的数,则x1为1,y1为大于等于2的数if y1 >= 2 and x1 == 1:return Trueelse:return Falsereturn False# 处理题目输入
n = int(input())
test_list = []
for i in range(n):test_list.append(int(input()))
print(test_list)start = time.time()
#获取素数表
pt1 = get_prime_table(10 ** 5)
for e in test_list:if can_frac(e, pt1):print("yes")else:print("no")
end = time.time()
print(end - start)
# 0.10699892044067383

以上算法只能处理a<=109a<=10^9a<=109的情况。主要耗时来源于获取素数表,求10510^5105范围内素数表大约耗时0.10699892044067383

难点在于当数位101810^{18}1018次方时获取素数表将非常耗时,最坏情况为一个数x1x_1x1​非常接近10910^{9}109,这个数的平方为a,即a=x12a=x_1^2a=x12​,如果是用以上方法查素数表,首先表的素数范围为10910^{9}109内的素数,其次x1x_1x1​要从2遍历到素数表末尾才能获取到a=x12a=x_1^2a=x12​。这两个步骤较为耗时的是获取10910^9109的素数表。

start = time.time()
pt1 = get_prime_table(10 ** 6)
end = time.time()
print(end - start)
# 2.228759288787842
# 10 ** 7
#44.911319732666016

可见当获取到10710^7107的素数表时,就已经不能满足题目要求的5s要求了。

所以只能考虑素数表在10510^5105范围内的情况。

分析二

据题,有两种情况满足题意。

情况一

aaa是某个素数的k次方,假设a=x1ka = x_1^{k}a=x1k​,其中x1x_1x1​为素数,k大于等于2。

此时考虑x1x_1x1​的范围,2≤x1≤a≤1018/22\le x_1\le \sqrt a \le 10^{18/2}2≤x1​≤a​≤1018/2,如果有x1x_1x1​满足题意,必然有x1=akx_1 = \sqrt[k]ax1​=ka​ 且x1x_1x1​是整数。

只要知道k的范围遍历即可。易知当x1=2x_1 = 2x1​=2时k有最大值为⌊log2a⌋+1\lfloor log_2^{a}\rfloor+1⌊log2a​⌋+1;当x1=a1/2x_1=a^{1/2}x1​=a1/2时k有最小值2。

情况一解法:

即使a=1018a = 10^{18}a=1018,也只需要遍历60步

# 判断是否为情况1,即为一个素数的k次方的情况。
def is_case_single_num(n):k = math.floor(math.log2(n)) + 1for i in range(2, k + 1):#python 区间左闭右开 if math.pow(n, 1 / i).is_integer():# 这里存在问题print(math.pow(n, 1 / i), i)#打印中间结果return Truereturn False

情况2

如果x1,x2≠1x_1,x_2\neq1x1​,x2​​=1,且y1,y2≥2y_1,y_2\ge 2y1​,y2​≥2,x1,x2x_1,x_2x1​,x2​为素数。

考虑x1,x2x_1,x_2x1​,x2​取到最大的情况(为了查表,求出素数表的上界),显然当y1,y2=2y_1,y_2=2y1​,y2​=2时,x1,x2x_1,x_2x1​,x2​有最大值。

即a=(x1×x2)2a =(x_1\times x_2)^2a=(x1​×x2​)2,此时x1x2≤1018/2=109x_1x_2\le10^{18/2}=10^9x1​x2​≤1018/2=109,不妨假设x1x_1x1​为较小值,x2x_2x2​为较大值。如果要满足题意,x1x_1x1​确定了则x2x_2x2​就确定了,即x1=k,x2=a/x1x_1=k,x_2=\sqrt a/x_1x1​=k,x2​=a​/x1​,并且当x1x_1x1​增加时x2x_2x2​就会减小,并且最多当x1=x2x_1 = x_2x1​=x2​时如果仍无解,那么就不会有解了。

当x1=x2时x_1=x_2时x1​=x2​时有a=(x1)4a=(x_1)^4a=(x1​)4,那么x1x_1x1​遍历的范围为[2,a4=1018/4=104.5][2,\sqrt[4]a=10^{18/4}=10^{4.5}][2,4a​=1018/4=104.5],所以素数表的范围只需要最多到10510^5105即可。

通过以上分析获取到x1x_1x1​所需要遍历素数表的范围后,即可轻易解出x1,y1x_1,y_1x1​,y1​,而且解出x1,y1x_1,y_1x1​,y1​后,a/x1y1a/x_1^{y_1}a/x1y1​​就退化为了情况1。至此分析完毕。

完整代码

def get_prime_table(n):prime_table = [2, 3, 5, 7]if n <= 10:return prime_tablefor i in range(11, n + 1, 2):j = 0len_prime_table = len(prime_table)flag = Truewhile j < len_prime_table and prime_table[j] < math.floor(math.sqrt(n)) + 1:if i % prime_table[j] == 0:flag = Falsebreakj += 1if flag:prime_table.append(i)return prime_table# 判断是否为情况1,即为一个素数的n次方的情况。
def is_case_single_num(n):# n_div = math.floor(math.sqrt(n)) + 1k = math.floor(math.log2(n)) + 1for i in range(2, k + 1):if math.pow(n, 1 / i).is_integer():print(math.pow(n, 1 / i), i)return Truereturn Falsedef can_frac(n, prime_table):x1 = ny1 = 0# 判断是否为情况1if is_case_single_num(n):return True# n_sqrt4 = n开4次根n_sqrt4 = math.floor(math.sqrt(math.floor(math.sqrt(n)) + 1)) + 1prime_len = len(prime_table)i = 0# 遍历素数表while i < prime_len and prime_table[i] < n_sqrt4:# 算出x1^{y1}while x1 % prime_table[i] == 0:x1 = x1 // prime_table[i]y1 += 1if y1 == 1: return False  # 如果y1等于1不满足题意# 退化为情况1if y1 >= 2:if is_case_single_num(x1):print(prime_table[i], y1)return Trueelse:return Falsei += 1return Falsen = int(input())
test_list = []
for i in range(n):test_list.append(int(input()))
start = time.time()
# xi 一定小于10^{4.5},素数表
pt1 = get_prime_table(10 ** 5)
for e in test_list:if can_frac(e, pt1):print("yes")else:print("no")
end = time.time()
print(end - start)

100000条耗时:6.964517831802368

【蓝桥杯2022】- 数的拆分相关推荐

  1. 第十三届蓝桥杯 2022年省赛真题(Java 大学C组)

    蓝桥杯 2022年省赛真题(Java 大学C组) 目录 试题 A: 排列字母 试题 B: 特殊时间 试题 C: 纸张尺寸 试题 D: 求和 试题 E: 矩形拼接 试题 F: 选数异或 试题 G: GC ...

  2. 蓝桥杯2022年B组初赛题解C++(待完善)

    文章目录 蓝桥杯2022年B组初赛题解C++ A题:九进制转十进制 B题:顺子日期 C题:刷题统计 D题:修剪灌木 E题:X进制减法 F题:统计子矩阵 G题:积木画 H题:扫雷 I题:李白打酒加酒加强 ...

  3. 蓝桥杯---特别数的和(C语言)

    蓝桥杯-特别数的和 解决方案: 1.从1遍历至n 2.确定每个数是否含有2.0.1.9 #include"stdio.h" int g(int a,int n){//遍历数的每一位 ...

  4. 蓝桥杯练习 数的读法

    蓝桥杯练习 数的读法 问题描述 Tom教授正在给研究生讲授一门关于基因的课程,有一件事情让他颇为头疼:一条染色体上有成千上万个碱基对,它们从0开始编号,到几百万,几千万,甚至上亿. 比如说,在对学生讲 ...

  5. 2032: [蓝桥杯2022初赛] 顺子日期

    2032: [蓝桥杯2022初赛] 顺子日期 内存限制:256 MB 时间限制:1 S 标准输入输出 题目类型:传统 评测方式:文本比较 上传者:外部导入 提交:384 通过:153 题目描述 小明特 ...

  6. P8775 [蓝桥杯 2022 省 A] 青蛙过河

    题目链接:[蓝桥杯 2022 省 A] 青蛙过河 - 洛谷 解法一:打暴力: 二分+模拟 很直接,不解释,肯定超时 代码: #include<iostream> #include<c ...

  7. 蓝桥杯2022砍竹子

    P2040 - [蓝桥杯2022初赛] 砍竹子 - New Online Judgehttp://oj.ecustacm.cn/problem.php?id=2040 #include <bit ...

  8. 蓝桥杯-幸运数(python)

    蓝桥杯-幸运数(python) 一.题目 时间限制: 1Sec 内存限制: 128MB 题目描述: 幸运数是波兰数学家乌拉姆命名的.它采用与生成素数类似的"筛法"生成 . 首先从1 ...

  9. java冰雹数10_蓝桥杯 冰雹数

    蓝桥杯 冰雹数 Java 冰雹数 任意给定一个正整数N, 如果是偶数,执行: N / 2 如果是奇数,执行: N * 3 + 1 生成的新的数字再执行同样的动作,循环往复. 通过观察发现,这个数字会一 ...

  10. 【洛谷】P8787 [蓝桥杯 2022 省 B] 砍竹子 的题解

    [洛谷]P8787 [蓝桥杯 2022 省 B] 砍竹子 的题解 题目传送门 思路 这个题有两个做法,一种是用 set 或者堆来维护一个高度到区间的映射,另一个用并查集维护区间. 这个题本质是一个最长 ...

最新文章

  1. [转]安装和使用JD-Eclipse插件
  2. python_day3作业
  3. 河南工程学院计算机科学与技术在哪个校区,河南工学院新生在哪个校区_有几个校区及地址介绍...
  4. python怎么封装方法然后调用_我现在想把自己写的python模块源代码封装成dll,然后在别的python脚本里调用,可以吗?...
  5. linux下storm集群配置,Twitter Storm 系统集群搭建
  6. 后端技术:数据持久化框架为什么放弃 Hibernate、JPA、Mybatis,最终选择 JDBCTemplate!...
  7. 工业以太网交换机的优势以及注意事项介绍
  8. matlab去除图片水印_(水印去除技巧)3个在线图片水印去除网站,值得收藏
  9. 最长递增子序列 动态规划
  10. pooling层如何反向传播? 很简单
  11. anaconda查看环境_快速搭建深度学习开发环境(以Pytorch为例)
  12. 小米便签开源项目本地环境搭建与分析
  13. clickhouse ARRAY JOIN函数
  14. 关于Palantir ——第六部分 – 图分析应用
  15. 逆向记录Assaultcube for Mac OS
  16. Git初步学习(一)
  17. 王海峰、李飞飞、山世光、王井东、汪玉……众多AI华人学者入选2022 IEEE Fellow...
  18. java继承1—上溯造型
  19. Spring Boot集成Mybatis-Plus多租户架构实战
  20. Python基本语法(二)

热门文章

  1. R语言绘图之ggplot2包
  2. 计算机网络ospf实验报告,计算机网络ospf实验报告.pdf
  3. 02#EXCEL函数【基础】
  4. regexp_substr()用法
  5. 『开发技巧』全网最详尽手把手教你在Ubuntu安装搜狗输入法
  6. JavaScript 网页购物车项目
  7. 将《2020中国统计年鉴》中的GDP数据换算成不变GDP数据
  8. 大数据推动磁带浴火重生 归档市场已超越云
  9. excel 使用技巧小总结
  10. 时间序列平稳性的统计检验