聪明的燕姿
聪明的燕姿
城市中人们总是拿着号码牌,不停寻找,不断匹配,可是谁也不知道自己等的那个人是谁。
可是燕姿不一样,燕姿知道自己等的人是谁,因为燕姿数学学得好!
燕姿发现了一个神奇的算法:假设自己的号码牌上写着数字 ,那么自己等的人手上的号码牌数字的所有正约数之和必定等于 。
所以燕姿总是拿着号码牌在地铁和人海找数字(喂!这样真的靠谱吗)。
可是她忙着唱《绿光》,想拜托你写一个程序能够快速地找到所有自己等的人。
输入格式
输入包含 组数据。
对于每组数据,输入包含一个号码牌 。
输出格式
对于每组数据,输出有两行。
第一行包含一个整数 ,表示有 个等的人。
第二行包含相应的 个数,表示所有等的人的号码牌。
注意:你输出的号码牌必须按照升序排列。
数据范围
,
输入样例:
42
输出样例:
3 20 26 41
解题思路
最近又重新做了下这道题,顺便看了下以前写的题解发现很多东西写得莫名奇妙的()
因此打算重新写过一篇,以前的题解就不删了,可以点击这里的链接查看:聪明的燕姿。
写完后发现还是很长,看不下去可以关掉,毕竟不敢对题解的质量进行保证qwq。
首先看到约数之和就很容易想到公式
因此问题就变成了有多少个质因子 以及对应的次幂 所构成的项 累乘得到的结果恰好为 。
看上去似乎没有很好的解决方法,那只能通过枚举所有的 和 来统计了。我们来分析一下暴搜的可行性,首先最多会有多少项进行累乘呢?通过放缩容易发现
因此递归的深度不会超过 层。所以在每一层中,我们可以从小到大来枚举质数 ,同时对于每个 也从小到大枚举对应的次幂 。为了防止重复搜索,当递归到下一场时我们规定必须从大于 的质数开始枚举,这样就能保证在得到的约数和中,有 。
那么质数 最大可以枚举到多少呢?首先很容易知道 一定小于 ,因为 和 本身就是 的两个约数,而 就超过 了,因此一定有 。所以按照上面的做法的,每一层枚举的质数都小于 ,由于最多要递归 层来枚举,因此计算量就达到 的级别(其中 表示不超过 的质数的个数)。我们继续看一下还有什么性质。
假设在约数之和的公式中存在某个质因子满足 ,那么该质因子对应的次幂 一定恰好为 ,即对应的项一定是 这个形式,而不可能是 这个形式。因为即使考虑 就已经有 ,此时约数之和就必定超过 了。
同时还可以发现如果存在某个质因子满足 ,那么该质因子就只能恰好是 这个最大的质因子。反证法,否则至少存在两个质因子满足 ,根据上面的结论必然有 ,此时的约数之和为
这就与约数之和为 矛盾了。
综合上面的结论,我们得到在约数之和的公式中,最多只会存在一个质因子 (即最大的那个质因子),且对应的次幂一定是 。
当 ,那么 。
当 ,有以下两种情况:
因此当我们枚举质因子 时只需要枚举到 就可以了,超过 的质因子 直接进行特判。假设之前枚举的 个质数得到的累乘结果记为 ,由于 必然是公式中最大的那个质因子,因此如果要满足 ,那么一定有 ,同时 是质数且 。
先给出这种搜索顺序的代码(其实这个搜索代码还是会 TLE):
1 void dfs(int cur, int prod, int num) { 2 if (prod == s) { 3 ans[sz++] = num; 4 return; 5 } 6 int r = s / prod; 7 if (is_prime(r - 1) && r - 1 >= primes[cur] && (r - 1) >= s / (r - 1)) ans[sz++] = num * (r - 1); 8 for (int i = cur; primes[i] <= s / primes[i]; i++) { 9 for (int j = 1 + primes[i], k = primes[i]; j <= s; k *= primes[i], j += k) { 10 if (r % j == 0) dfs(i + 1, prod * j, num * k); 11 } 12 } 13 }
先解释以下各个参数的含义,首先 表示当前从第 个质数开始枚举。 的定义与上面相同,即之前枚举质数的各项累乘。 表示约数之和为 所对应的那个数,即 的约数之和等于 。
很明显当 ,那么此时 就是我们要找的数。
否则我们先判断是否存在质因子 使得 ,在代码中 。如果满足 是质数,且 ,那么 就是我们要找的答案。
然后再去枚举考虑不超过 的质因子,以及对应的次幂,往下一层递归。
可是这样做还是会超时的,因为计算量大概是 级别。继续对枚举质数的部分进行优化,可以发现在每一层中我们做的事情都是从第 个质数开始枚举,使得累乘的结果不超过 。类比上面的分析,我们知道枚举的质数肯定要小于 ,并且一样可以枚举不超过 的质数,然后超过 的质因子进行特判就可以了,代码就变成下面的样子:
1 void dfs(int cur, int prod, int num) { 2 if (prod == s) { 3 ans[sz++] = num; 4 return; 5 } 6 int r = s / prod; 7 if (is_prime(r - 1) && (r - 1) >= primes[cur]) ans[sz++] = num * (r - 1); 8 for (int i = cur; primes[i] <= r / primes[i]; i++) { 9 for (int j = 1 + primes[i], k = primes[i]; j <= r; k *= primes[i], j += k) { 10 if (r % j == 0) dfs(i + 1, prod * j, num * k); 11 } 12 } 13 }
可以发现少了判断条件 (r - 1) >= r / (r - 1) ,这是因为 一定大于 。这个搜索代码就可以过了。
至此搜索的部分就已经讲完了,剩下的就只需要筛出不超过 的所有质数,以及写个判断是否为质数的函数就可以了。
AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 45000; 5 6 int s; 7 int primes[N], cnt; 8 bool vis[N]; 9 int ans[N], sz; 10 11 void get_prime(int n) { 12 for (int i = 2; i <= n; i++) { 13 if (!vis[i]) primes[cnt++] = i; 14 for (int j = 0; primes[j] <= n / i; j++) { 15 vis[primes[j] * i] = true; 16 if (i % primes[j] == 0) break; 17 } 18 } 19 } 20 21 bool is_prime(int x) { 22 if (x < N) return !vis[x]; 23 for (int i = 0; primes[i] <= x / primes[i]; i++) { 24 if (x % primes[i] == 0) return false; 25 } 26 return true; 27 } 28 29 void dfs(int cur, int prod, int num) { 30 if (prod == s) { // 搜索得到的质数和prod等于s 31 ans[sz++] = num; 32 return; 33 } 34 int r = s / prod; // 要凑的剩余部分 35 if (is_prime(r - 1) && (r - 1) >= primes[cur]) ans[sz++] = num * (r - 1); // 先考虑质因子大于sqrt(r)的情况 36 for (int i = cur; primes[i] <= r / primes[i]; i++) { // 再考虑质因子小于sqrt(r)的情况 37 for (int j = 1 + primes[i], k = primes[i]; j <= r; k *= primes[i], j += k) { // 枚举质数i对应的次幂 38 if (r % j == 0) dfs(i + 1, prod * j, num * k); 39 } 40 } 41 } 42 43 int main() { 44 get_prime(N - 1); // 筛出不超过sqrt(2e9)的质数 45 while (~scanf("%d", &s)) { 46 sz = 0; 47 dfs(0, 1, 1); // 从第0个质数开始枚举搜索 48 printf("%d\n", sz); 49 if (sz) { 50 sort(ans, ans + sz); 51 for (int i = 0; i < sz; i++) { 52 printf("%d ", ans[i]); 53 } 54 printf("\n"); 55 } 56 } 57 58 return 0; 59 }
参考资料
聪明的燕姿:https://www.cnblogs.com/onlyblues/p/15966022.html
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17206228.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效