BZOJ3994 约数个数和
3994: [SDOI2015]约数个数和
Time Limit: 20 Sec Memory Limit: 128 MBDescription
设d(x)为x的约数个数,给定N、M,求
Input
输入文件包含多组测试数据。
第一行,一个整数T,表示测试数据的组数。
接下来的T行,每行两个整数N、M。
Output
T行,每行一个整数,表示你所求的答案。
Sample Input
2
7 4
5 6
7 4
5 6
Sample Output
110
121
121
HINT
1<=N, M<=50000
1<=T<=50000
结论题丧心病狂系列
其实看到这道题,我们发现最大的难点就是如何求\( d(nm) \)
暂且不说为什么,我们欣赏一下这个式子\[ d(nm)=\sum_{i \mid n}\sum_{j \mid m}\lbrack gcd(i,j)=1 \rbrack \]
其实我刚看到的时候是拒绝的,什么鬼啊???!!!
然后我们抛开这个式子,来分析一下某个质数\(p\)对答案的贡献
若\( n=n’ \times p^{k_{1}} \), \( m=m’ \times p^{k_{2}} \)
则贡献为\( k_{1}+k_{2}+1 \)
然后我们观察开始给出的式子,发现一个素数对答案有贡献的还是\( (p^{k_{1}},1),(p^{k_{1}-1},1) \cdots (1,1) \cdots (1,p^{k_{2}-1}),(1,p^{k_{2}}) \)这\( k_{1}+k_{2}+1 \)个
所以我们证明了这个结论的成立。
接下来是莫比乌斯反演的正常推导
最终形式为\[ \sum_{g=1}^{N}\mu(g)\sum_{i=1}^{\lfloor \frac{N}{g} \rfloor}\sum_{j=1}^{\lfloor \frac{M}{g} \rfloor}\lfloor \frac{N}{ig} \rfloor\lfloor \frac{M}{jg} \rfloor \]
1 #include<bits/stdc++.h> 2 using namespace std; 3 template <class _T> inline void read(_T &_x) { 4 int _t; bool flag = false; 5 while ((_t = getchar()) != '-' && (_t < '0' || _t > '9')) ; 6 if (_t == '-') _t = getchar(), flag = true; _x = _t - '0'; 7 while ((_t = getchar()) >= '0' && _t <= '9') _x = _x * 10 + _t - '0'; 8 if (flag) _x = -_x; 9 } 10 typedef long long LL; 11 const int maxn = 50010; 12 int f[maxn], mu[maxn], prime[maxn], pcnt; 13 bool vis[maxn]; 14 inline int calc_f(int n) { 15 int ret = 0; 16 for (int i = 1, j, t; i <= n; i = j + 1) { 17 t = n / i, j = n / t; 18 ret += t * (j - i + 1); 19 } 20 return ret; 21 } 22 inline void init() { 23 mu[1] = 1; 24 for (int i = 2; i < maxn; ++i) { 25 if (!vis[i]) { 26 prime[++pcnt] = i; 27 mu[i] = -1; 28 } 29 for (int j = 1; j <= pcnt && prime[j] * i < maxn; ++j) { 30 vis[prime[j] * i] = true; 31 if (i % prime[j] == 0) { 32 mu[prime[j] * i] = 0; 33 break; 34 } 35 mu[prime[j] * i] = -mu[i]; 36 } 37 } 38 for (int i = 1; i < maxn; ++i) { 39 mu[i] += mu[i - 1]; 40 f[i] = calc_f(i); 41 } 42 } 43 inline LL calc(int n, int m) { 44 if (n > m) swap(n, m); 45 LL ret = 0; 46 for (int i = 1, j, t1, t2; i <= n; i = j + 1) { 47 t1 = n / i, t2 = m / i, j = min(n / t1, m / t2); 48 ret += (mu[j] - mu[i - 1]) * ((LL)f[t1] * f[t2]); 49 } 50 return ret; 51 } 52 int n, m; 53 int main() { 54 //freopen(".in", "r", stdin); 55 //freopen(".out", "w", stdout); 56 init(); 57 int T; read(T); 58 while (T--) { 59 read(n), read(m); 60 printf("%lld\n", calc(n, m)); 61 } 62 return 0; 63 }
作者:HPL 出处:https://www.cnblogs.com/akhpl/ 感谢您的阅读,如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮。本文由CC BY-NC-ND 2.5授权,欢迎读者转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,谢谢。