扩大
缩小

BZOJ3994 约数个数和

3994: [SDOI2015]约数个数和

Time Limit: 20 Sec  Memory Limit: 128 MB

Description

 设d(x)为x的约数个数,给定N、M,求  

Input

输入文件包含多组测试数据。

第一行,一个整数T,表示测试数据的组数。
接下来的T行,每行两个整数N、M。 

Output

T行,每行一个整数,表示你所求的答案。 

Sample Input

2
7 4
5 6

Sample Output

110
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 }
View Code

 

 
posted @ 2017-05-08 18:17  HPLV  阅读(213)  评论(0编辑  收藏  举报