bzoj3629: [JLOI2014]聪明的燕姿(数学 + 搜索)

bzoj3629

题目描述:给定一个数s,求约数之和等于s的所有数。

输入格式:输入包含k组(k <= 100),每组一个整数s。

输出格式:对于每组数据,输出两行,第一行一个整数,表示总数,第二行表示所有的数。

样例输入:

42

样例输出:

3
20 26 41

解析:相信大家都很熟悉约数和定理,那么这题便可以用搜索来解决,搜索枚举因数即可。(好像还是搜索比较难打)

代码如下:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define int long long
 4 using namespace std;
 5 
 6 const int maxn = 1e5;
 7 int s, prime[maxn], mark[maxn], ans[maxn], cnt, tot;
 8 
 9 void prepare(void) { //欧拉筛 
10     mark[1] = 1;
11       for (int i = 1; i <= maxn; ++ i) {
12           if (!mark[i]) prime[++ tot] = i;
13           for (int j = 1; j <= tot; ++ j) {
14               if (1ll * prime[j] * i > maxn) break;
15               mark[prime[j] * i] = 1;
16           }
17       }
18 }
19 
20 int pd(int num) { //判断素数
21     if (num <= maxn) return !mark[num]; //如果找过了就直接用
22     if (num == 1) return 0; //特判1不是素数 
23     for (int i = 1; 1ll * prime[i] * prime[i] <= num; ++ i) //试除
24       if (num % prime[i] == 0) return 0;
25     return 1;
26 }
27 
28 void dfs(int last, int prod, int rest) { //last:上一个搜的素数,prod:搜到的数,rest:还需要乘上rest达到s
29     if (rest == 1) { //累加答案  
30       ans[++ cnt] = prod;
31       return;
32     }
33     if (rest - 1 > prime[last] && pd(rest - 1)) ans[++ cnt] = prod * (rest - 1); //rest - 1要大于prime[last],否则会重复枚举(不用return!) 
34     for (int i = last + 1; prime[i] * prime[i] <= rest; ++ i) {
35       for (int j = prime[i], cur = prime[i] + 1; cur <= rest; j *= prime[i], cur += j) { //j是约数的次幂,cur是约数的和 
36           if (rest % cur == 0) dfs(i, prod * j, rest / cur);
37       }
38     } 
39 }
40 
41 signed main() {
42     prepare();
43     while (scanf("%lld", &s) != EOF) {
44       cnt = 0; dfs(0, 1, s); 
45       sort(ans + 1, ans + 1 + cnt);
46       printf("%lld
", cnt);
47         for (int i = 1; i <= cnt; ++ i) printf("%lld%c", ans[i], i == cnt ? '
' : ' ');
48     }
49     return 0;
50 } 
原文地址:https://www.cnblogs.com/Gaxc/p/9915789.html