1. 程式人生 > >【BZOJ4176】 Lucas的數論

【BZOJ4176】 Lucas的數論

ima () 截圖 sample 需要 但是 100% 個數 return

Description

去年的Lucas非常喜歡數論題,但是一年以後的Lucas卻不那麽喜歡了。

在整理以前的試題時,發現了這樣一道題目“求Sigma(f(i)),其中1<=i<=N”,其中 表示i的約數個數。他現在長大了,題目也變難了。 求如下表達式的值: 技術分享 其中 表示ij的約數個數。 他發現答案有點大,只需要輸出模1000000007的值。

Input

第一行一個整數n。

Output

一行一個整數ans,表示答案模1000000007的值。

Sample Input

2

Sample Output

8

HINT

對於100%的數據n <= 10^9。

Solution

因為直接用編輯器打公式比較麻煩且醜,就用markdown截圖完傳圖片了= =b。

技術分享

技術分享

Code

 1 #include <cstdio>
 2 #include <cmath>
 3 
 4 #define R register
 5 const int mod = 1e9 + 7;
 6 #define maxn 1500010
 7 int miu[maxn], smiu[maxn], pr[maxn / 10], prcnt, lim, N;
 8 bool vis[maxn];
 9 int hash[maxn];
10 bool vihash[50000]; 11 int Miu(R int n) 12 { 13 if (n <= lim) return smiu[n]; 14 if (vihash[N / n]) return hash[N / n]; 15 16 vihash[N / n] = 1; 17 R int ret = 1; 18 for (R int i = 2, j; i <= n; i = j + 1) 19 { 20 j = n / (n / i); 21 (ret += mod - 1ll * (j - i + 1
) * Miu(n / i) % mod) %= mod; 22 } 23 return hash[N / n] = ret; 24 } 25 inline int sumf(R int n) 26 { 27 R int ret = 0; 28 for (R int i = 1, j; i <= n; i = j + 1) 29 { 30 j = n / (n / i); 31 ret = (ret + 1ll * (j - i + 1) * (n / i)) % mod; 32 } 33 return ret; 34 } 35 int main() 36 { 37 scanf("%d", &N); 38 lim = (int) pow(N * 1.0, 0.666); 39 // printf("%d\n", lim); 40 miu[1] = smiu[1] = 1; 41 for (R int i = 2; i <= lim; ++i) 42 { 43 if (!vis[i]) pr[++prcnt] = i, miu[i] = -1; 44 smiu[i] = (smiu[i - 1] + miu[i]) % mod; 45 for (R int j = 1; j <= prcnt && 1ll * i * pr[j] <= lim; ++j) 46 { 47 vis[i * pr[j]] = 1; 48 if (i % pr[j]) miu[i * pr[j]] = -miu[i]; 49 else 50 { 51 miu[i * pr[j]] = 0; 52 break; 53 } 54 } 55 } 56 R int ans = 0, last = 0; 57 for (R int i = 1, j; i <= N; i = j + 1) 58 { 59 j = N / (N / i); 60 R int Ph = Miu(j); 61 R int fs = sumf(N / i); 62 // printf("l = %d r = %d %d %d\n", i, j, Ph, fs); 63 ans = (ans + 1ll * (Ph - last + mod) * fs % mod * fs) % mod; 64 last = Ph; 65 } 66 // printf("%d\n", last); 67 printf("%d\n", ans % mod); 68 return 0; 69 }

【BZOJ4176】 Lucas的數論