用到了算數基本定理的思想,尤拉篩的不記錄最小質因子的板子,另外在優化dfs的時候還用到了小學生求素數的一點小思想,下面我們簡單說一下思路和分析幾個問題。
思路:正約數之和等於s的數,容易想到直接列舉每乙個質數與每乙個質數的數量,然後進行優化。
第乙個問題:尤拉篩存質數的陣列到底開多大?
這個問題,誰一開始寫這個**也不知道,除非花了很多時間分析,所以我們先保留這個問題。
第二個問題:如何優化列舉。
(1)先列舉數量還是先列舉質數?
答:先列舉質數比較好,因為我們可以讓下一次dfs呼叫,列舉素數開始的位置為上一次列舉素數結果的下一項,也是一種小優化。
(2)列舉素數的終止條件是什麼?
**答:**我們每一層dfs都有乙個now表示的是s除以每一層dfs得到的乘數之後的結果,只有(1+p+p^2+…+ p ^ k) 為因子時,我們才算找到乙個結果,那麼對於很大的p來說,只要p>sqrt(now),那麼其實到1+p+p ^ 2 來說,乘數就已經比now還要大了,那麼其實我們對每一層的dfs就可以就行如下優化了
1.判斷1+p (這裡的p我們預設為大於sqrt(now))是否等於now,然後判斷p是否為素數,這樣就排除了所有大於sqrt(now)的p的正解。
2.列舉素數時,我們只列舉sqrt(now)以內的素數,列舉數量時,列舉到(1+p+p^2+…+ p ^ k) 小於等於now即可
最後悄悄說一句:wlz是傻dei
1296. 聰明的燕姿
城市中人們總是拿著號碼牌,不停尋找,不斷匹配,可是誰也不知道自己等的那個人是誰。
可是燕姿不一樣,燕姿知道自己等的人是誰,因為燕姿數學學得好!
燕姿發現了乙個神奇的演算法:假設自己的號碼牌上寫著數字 s,那麼自己等的人手上的號碼牌數字的所有正約數之和必定等於 s。
所以燕姿總是拿著號碼牌在地鐵和人海找數字(喂!這樣真的靠譜嗎)。
可是她忙著唱《綠光》,想拜託你寫乙個程式能夠快速地找到所有自己等的人。
輸入格式
輸入包含 k 組資料。
對於每組資料,輸入包含乙個號碼牌 s。
輸出格式
對於每組資料,輸出有兩行。
第一行包含乙個整數 m,表示有 m 個等的人。
第二行包含相應的 m 個數,表示所有等的人的號碼牌。
注意:你輸出的號碼牌必須按照公升序排列。
資料範圍
1≤k≤100,
1≤s≤2×109
輸入樣例:
42輸出樣例:
320 26 41
#include#include#include#include#includeusing namespace std;
const int n = 1 * 1e6 + 15;
typedef long long ll;
int s,cmy,k;
int res[n];
ll p[n];
bool book[n];
void oula()
for(int j = 1; j <= cmy && p[j] * i < n; j ++)
}}bool is_prime(ll x)
}void dfs(int last, ll now, ll sniper)
if(now - 1 > p[last] && is_prime(now - 1))
for(int i = last + 1; i <= cmy && p[i] * p[i] <= now; i ++) }
}int main()
else printf(" %d",res[i]);
} if(k) puts("");
} return 0;
}
AcWing1296 聰明的燕姿
解題思路 首先我們肯定要用到約數之和定理 但是有個問題就是要怎麼用 根據經驗得知,約數最多也就六七個左右,不然直接就超了s的範圍。所以我們考慮用爆搜來做 但是用爆搜的話還是要優化一下思路和用什麼順序去搜尋。順序 按照p和 的順序來列舉 一旦s 這個當前的乘積 0 dfs的精髓 那才能跳到下一層迴圈因...
AcWing 1296 聰明的燕姿
原題鏈結 考察 dfs 約數 錯誤思路 倍數法求出所有約數,n要開到1e9必然mle且tle 正確思路 觀察約數之和的式子 s 1 p1 p1 2 p1 3 1 p2 p2 2 p2 3 要滿足能夠這種性質的數在1 2e9內較少.再繼續觀察,假設p全為2,1 2 1 2 22 1 2 22 23 當...
AcWing 1296 聰明的燕姿
算術基本定理 任何乙個大於1的自然數 n,如果n不為質數,那麼n可以唯一分解成有限個質數的乘積 則可以對s進行分解質因數 s p1 p2 pn 根據約數之和 sum 1 p1 1 p1 2 p1 1 pn 1 pn 而任何約數之和為s的數一定可以表示為約束之和公式的形式,即 s sum 因此除了1 ...