【題目描述】給定n,求全部小於等於n的數,與n的最大公約數之和。ide 【輸入】輸入包含一個非負整數n。函數 【輸出】輸出一個整數,爲求和的結果。spa 【輸入樣例】10 【輸出樣例】27 【提示】對於40%的數據點,1<=n<=10^5。code 對於60%的數據點,1<=n<=10^7。blog 對於100%的數據點,1<=n<=10^9。get |
好,這道題我現場莫比烏斯反演AC,正解是歐拉函數0ms,反演跑的慢些,100ms...反正我也不會歐拉函數。數學
下面由我來說解如何A題。io
按照套路,設event
則有table
推出來三個式子,目測最下面那個好一些,就選它了!
miu(1e9)顯然不能直接求。
我預處理出來1e7之內的miu,多餘的就按照定義暴力計算。
複雜度上界是
可是跑起來飛快...
1 #include <cstdio> 2 typedef long long LL; 3 const int N = 10000010; 4 5 int miu[N], n, p[N], top; 6 bool vis[N]; 7 8 inline int F(int x) { 9 return n / x; 10 } 11 12 inline void getmiu(int b) { 13 miu[1] = 1; 14 b = b >= N ? N - 1 : b; 15 for(int i = 2; i <= b; i++) { 16 if(!vis[i]) { 17 p[++top] = i; 18 miu[i] = -1; 19 } 20 for(int j = 1; j <= top && i * p[j] <= b; j++) { 21 vis[i * p[j]] = 1; 22 if(i % p[j] == 0) { 23 break; 24 } 25 miu[i * p[j]] = -miu[i]; 26 } 27 } 28 return; 29 } 30 31 inline int u(int x) { 32 if(x < N) { 33 return miu[x]; 34 } 35 int t = 0; 36 for(int i = 1; i <= top && p[i] * p[i] <= x; i++) { 37 if(x % p[i] == 0) { 38 t++; 39 x /= p[i]; 40 if(x % p[i] == 0) { 41 return 0; 42 } 43 } 44 } 45 if(x > 1) { 46 t++; 47 } 48 return t & 1 ? -1 : 1; 49 } 50 51 inline LL solve(int i) { 52 LL ans = 0; 53 for(int d = 1; d * d <= i; d++) { 54 if(i % d == 0) { 55 ans += i / d * u(d); 56 if(d * d < i) { 57 ans += d * u(i / d); 58 } 59 } 60 } 61 return ans * F(i); 62 } 63 64 int main() { 65 //freopen("a.in", "r", stdin); 66 //freopen("a.out", "w", stdout); 67 LL ans = 0; 68 69 scanf("%d", &n); 70 getmiu(n); 71 for(int i = 1; i * i <= n; i++) { 72 if(n % i == 0) { 73 ans += solve(i); 74 if(i * i < n) { 75 ans += solve(n / i); 76 } 77 } 78 } 79 printf("%lld", ans); 80 return 0; 81 }
而後嘗試中間那個式子。
注意F(i)當i不是n的約數的時候值爲0,上面那個式子調用的i都是n的約數,因此沒加判斷能夠過。
第二個式子光榮犧牲,60分TLE
1 #include <cstdio> 2 typedef long long LL; 3 const int N = 10000010; 4 5 int miu[N], n, p[N], top; 6 bool vis[N]; 7 8 inline int F(int x) { 9 if(n % x) { 10 return 0; 11 } 12 return n / x; 13 } 14 15 inline void getmiu(int b) { 16 miu[1] = 1; 17 b = b >= N ? N - 1 : b; 18 for(int i = 2; i <= b; i++) { 19 if(!vis[i]) { 20 p[++top] = i; 21 miu[i] = -1; 22 } 23 for(int j = 1; j <= top && i * p[j] <= b; j++) { 24 vis[i * p[j]] = 1; 25 if(i % p[j] == 0) { 26 break; 27 } 28 miu[i * p[j]] = -miu[i]; 29 } 30 } 31 return; 32 } 33 34 inline int u(int x) { 35 if(x < N) { 36 return miu[x]; 37 } 38 int t = 0; 39 for(int i = 1; i <= top && p[i] * p[i] <= x; i++) { 40 if(x % p[i] == 0) { 41 t++; 42 x /= p[i]; 43 if(x % p[i] == 0) { 44 return 0; 45 } 46 } 47 } 48 if(x > 1) { 49 t++; 50 } 51 return t & 1 ? -1 : 1; 52 } 53 54 inline LL solve(int d) { 55 LL ans = 0; 56 for(int i = 1; i * d <= n; i++) { 57 ans += 1ll * u(i) * F(i * d); 58 } 59 return ans; 60 } 61 62 int main() { 63 LL ans = 0; 64 65 scanf("%d", &n); 66 getmiu(n); 67 for(int d = 1; d * d <= n; d++) { 68 if(n % d == 0) { 69 ans += d * solve(d); 70 if(d * d < n) { 71 int t = n / d; 72 ans += t * solve(t); 73 } 74 } 75 } 76 printf("%lld", ans); 77 return 0; 78 }
第一個式子和第二個本質相同。
總結:這更像是數學題...重要的是分辨哪一個跑得快。若是不能肯定能夠打出來比較一下。