0
点赞
收藏
分享

微信扫一扫

LOJ #2234. 「JLOI2014」聪明的燕姿 && 约数和、约数个数定理复习


题目链接:​​传送门​​

题目中明显地提到了约数和
那我们自然先想到唯一分解定理,约数个数定理,约数和定理
一个大于的整数可以唯一分解成
这个数的约数就是
这些约数的和就是
用式子写出来就是
第二个连乘还可以写成
的规模是,所以其实的规模也不会特别大
那么直接通过深搜的所有情况
也就是搜索出现次数的所有情况
等于的数出现就会出现一次,大于的数也最多出现
主要是理解一下深搜的过程

#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;
}


举报

相关推荐

0 条评论