P1463 [POI2002][HAOI2007]反素數
阿新 • • 發佈:2018-10-01
pragma 唯一分解定理 scan 優化 個數 c++ printf line 不知道
打表出奇跡!!!
這道題暴力當然能做,但是\(n==2 \times 10 ^9\)就不允許暴力了。
讓我們打表出奇跡!!!
首先先了解一下如何有效率地算出一個數的約數個數:
最暴力的是從\(1\)枚舉到\(n\),每一次++。
優化一點的就是只枚舉到\(\sqrt{n}\)。但是還是很慢的。
我們了解一下傳說的約數個數定理:
對於一個正整數\(n\),由唯一分解定理可以分解為\(p_1^{a_1} \times p_2^{a_2} \times ... \times p_i^{a_i}\)。
那麽這個約數個數就是\((a_1+1)(a_2+1)...(a_i+1)\)。
所以我們就能夠用比較好的時間復雜度寫出這個打表程序了。
因為唯一分解定理需要的是質數,所以我們就能除以當前的質數就除,不能除就下一個,直到為1為止。
因為前10個質數的積已經大於2e9,所以直接人工打出前10個質數。
這是打表程序:
#pragma optimize(2) //我也學會了這個手動O2 #include<cstdio> const int maxn = 2000000005; const int N = maxn - 5; const int prime[] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29};// 10 int maxv; int main() { freopen("out.txt", "w", stdout); for(int i = 2; i <= N; i++) { int temp = i, ans = 1; for(int j = 1; j <= 10; j++) { int cnt = 0; while(temp % prime[j] == 0) { temp = temp / prime[j]; cnt++; } ans = ans * (cnt + 1); if(temp == 1) break; } if(ans > maxv) { printf("%d\n", i); maxv = ans; } } return 0; }
這份代碼運行完是有180s左右,比上面第二種算法快了不知道多少。
然後我再去轉換一下,把這些數字用C++輸出成一個常量數組,就成為我們的表了。
然後主程序就非常無腦了:
#include<cstdio> int g[] = {0, 2, 4, 6, 12, 24, 36, 48, 60, 120, 180, 240, 360, 720, 840, 1260, 1680, 2520, 5040, 7560, 10080, 15120, 20160, 25200, 27720, 45360, 50400, 55440, 83160, 110880, 166320, 221760, 277200, 332640, 498960, 554400, 665280, 720720, 1081080, 1441440, 2162160, 2882880, 3603600, 4324320, 6486480, 7207200, 8648640, 10810800, 14414400, 17297280, 21621600, 32432400, 36756720, 43243200, 61261200, 73513440, 110270160, 122522400, 147026880, 183783600, 245044800, 294053760, 367567200, 551350800, 698377680, 735134400, 1102701600, 1396755360}; // 67 int main() { int n; scanf("%d", &n); for(int i = 1; i <= 67; i++) { if(g[i] > n && g[i - 1] <= n) { printf("%d\n", g[i - 1]); return 0; } } printf("%d\n", g[67]); return 0; }
P1463 [POI2002][HAOI2007]反素數