Address
https://www.lydsy.com/JudgeOnline/problem.php?id=3629
Solution
根据小学知识,如果一个正整数
的标准分解形式为
,那么
的约数和为:
我们可以大力搜索每个质因数的出现次数。
不过有一些技巧,否则 TLE :
(1)大于 的因子最多一个,因此搜完 以内的质因子且当前讨论到 时,只需要判断是否 , 大于 且为质数即可。当然,如果 就无须讨论这一点。
(2)尽管 的约数不是很多,但我们还是可以构造出一些 使 比较大,比如 。为了降低复杂度,我们还需要将 以内的质数 从大到小枚举,避免 dfs 时在无解的节点上浪费过多时间。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
using namespace std;
const int N = 1e6 + 5, M = 5e4 + 5;
int n, m, len, ans[N], MaxN, tot, pri[M];
bool mark[N];
inline bool Pri(const int &n) {
int i, S = sqrt(n);
For (i, 2, S) if (n % i == 0) return 0;
return 1;
}
void sieve() {
int i, j;
MaxN = sqrt(n);
For (i, 0, 50000) mark[i] = 0;
mark[0] = mark[1] = 1;
For (i, 2, 50000) {
if (!mark[i]) {
pri[++tot] = i;
if (i <= MaxN) len = tot;
}
For (j, 1, tot) {
if (1ll * i * pri[j] > 1000000) break;
mark[i * pri[j]] = 1;
if (i % pri[j] == 0) break;
}
}
}
inline void dfs(const int &dep, const int &num, const int &sum) {
if (sum == n) return (void) (ans[++m] = num);
if (dep == len + 1) {
if (n / sum - 1 > MaxN && Pri(n / sum - 1))
ans[++m] = num * (n / sum - 1);
return;
}
int i, s = 1, q = 1;
For (i, 0, 998244353) {
if (n % (s * sum) == 0) dfs(dep + 1, num * q, sum * s);
if ((1ll * q * pri[len - dep + 1] + s) * sum > n) break;
s += (q *= pri[len - dep + 1]);
}
}
void work() {
int i; m = tot = 0;
sieve();
dfs(1, 1, 1);
printf("%d\n", m);
sort(ans + 1, ans + m + 1);
For (i, 1, m) printf("%d ", ans[i]);
if (m) printf("\n");
}
int main() {
while (~scanf("%d", &n)) work();
return 0;
}