题目链接:传送门
题目中明显地提到了约数和
那我们自然先想到唯一分解定理,约数个数定理,约数和定理
一个大于的整数可以唯一分解成
这个数的约数就是
这些约数的和就是
用式子写出来就是和
第二个连乘还可以写成的规模是
,所以其实
和
的规模也不会特别大
那么直接通过深搜
和
的所有情况
也就是搜索出现次数的所有情况
等于
的数出现就会出现一次,
大于
的数也最多出现
次
主要是理解一下深搜的过程
#include <bits/stdc++.h>
#define
using namespace std;
typedef long long ll;
int bz[A], pri[A], cnt, s, p[A], k;
bool check(int x) {
if (x < 100000) return !pri[x];
int kj = sqrt(1.0 * x);
for (int i = 2; i <= kj; i++) if (x % i == 0) return false;
return true;
}
void dfs(int now, int x, int s) { //now是当前枚举到了第几个质数,x是前面的质数的积,s就是约数和
if (s == 1) {p[++k] = x; return;}
if (s - 1 > bz[now] and check(s - 1)) p[++k] = (s - 1) * x;
int kj = sqrt(1.0 * s); //找根号s以内的质数,大了没有意义反正统计不进答案
for (int i = now + 1; i <= cnt and bz[i] <= kj; i++) {
int tmp = bz[i];
for (int j = tmp + 1; j <= s; tmp *= bz[i], j += tmp) if (s % j == 0) dfs(i, x * tmp, s / j);
}
}
int main(int argc, char const *argv[]) {
for (int i = 2; i <= 100000; i++) {
if (!pri[i]) bz[++cnt] = i;
for (int j = 1; j <= cnt and bz[j] * i < 100000; j++) {
pri[i * bz[j]] = 1;
if (i % bz[j] == 0) break;
}
}
while (cin >> s) {
k = 0; dfs(0, 1, s);
sort(p + 1, p + k + 1);
k = unique(p + 1, p + k + 1) - p - 1;
printf("%d\n", k);
for (int i = 1; i <= k; i++) printf("%d ", p[i]); puts("");
}
return 0;
}