LiberOJ #124. 除数函数求和 【整除分块】

一、题目

  #124. 除数函数求和

二、分析

  比较好的一题,首先我们要对题目和样例进行分析,明白题目的意思。

  由于对于每一个$d$,它所能整除的数其实都是定的,且数量是$ \lfloor \frac{n}{d} \rfloor $ 最终推导出这个公式 $$  ans =   \sum_{d=1}^{n} \lfloor \frac{n}{d} \rfloor d^{k}$$

  对于$n <= 10^{7}$其实复杂度是可以接受的。但是对于求$d^{k}$这个复杂度如果直接用快速幂预处理肯定会T。

  所以,这里用到了一个比较巧妙的方法,即联系线性求欧拉函数,因为幂次方是可以直接相乘的,所以把每个数相当于拆成了素数的$k$次方,这样我们原先求$n$次的快速幂,现在只需要求$\sqrt{n}$次快速幂,即所有素数求一次。然后线性筛一遍就可以了。

三、AC代码

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 #define ll long long
 5 const int mod = 1e9 + 7;
 6 const int maxn = 1e7 + 13;
 7 int Sum[maxn], Prime[maxn], tot;
 8 bool isPrime[maxn];
 9 int n, k;
10 
11 int Pow(int a, int b)
12 {
13     int ans = 1;
14     while(b)
15     {
16         if(b & 1)
17         {
18             ans = 1ll * ans * a % mod;
19         }
20         b >>= 1;
21         a = 1ll * a * a % mod;
22     }
23     return ans;
24 }
25 
26 void init()
27 {
28     tot = 0;
29     memset(isPrime, 0, sizeof(isPrime));
30     isPrime[0] = isPrime[1] = 1;
31     Sum[1] = 1;
32     for(int i = 2; i < maxn; i++)
33     {
34         if(!isPrime[i])
35         {
36             Prime[tot++] = i;
37             Sum[i] = Pow(i, k);
38         }
39         for(int j = 0; j < tot && 1ll * Prime[j] * i < maxn; j++)
40         {
41             isPrime[i * Prime[j]] = 1;
42             Sum[i * Prime[j]] = 1ll * Sum[i] * Sum[Prime[j]] % mod;
43             if(i % Prime[j])
44                 break;
45         }
46     }
47 }
48 
49 int main()
50 {
51     int ans = 0;
52     cin >> n >> k;
53     init();
54     for(int i = 1; i <= n; i++)
55     {
56         int t = n / i;
57         ans = (ans + 1ll * t * Sum[i] % mod) % mod; 
58     }
59     cout << ans << endl;
60     return 0;
61 }

 

posted @ 2019-07-25 16:57  Dybala21  阅读(278)  评论(0编辑  收藏  举报