bzoj3629: [JLOI2014]聪明的燕姿(数学 + 搜索)
题目描述:给定一个数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\n", cnt); 47 for (int i = 1; i <= cnt; ++ i) printf("%lld%c", ans[i], i == cnt ? '\n' : ' '); 48 } 49 return 0; 50 }