1. 程式人生 > >bzoj3629: [JLOI2014]聰明的燕姿

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\n", cnt); 47 for (int i = 1; i <= cnt; ++ i) printf("%lld%c", ans[i], i == cnt ? '\n' : ' '); 48 } 49 return 0; 50 }