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
brack ]
其实我刚看到的时候是拒绝的,什么鬼啊???!!!
然后我们抛开这个式子,来分析一下某个质数(p)对答案的贡献
若( n=n’ imes p^{k_{1}} ), ( m=m’ imes 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}
floor}sum_{j=1}^{lfloor frac{M}{g}
floor}lfloor frac{N}{ig}
floorlfloor frac{M}{jg}
floor ]
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 ", calc(n, m)); 61 } 62 return 0; 63 }