3994: [SDOI2015]约数个数和
Time Limit: 20 Sec Memory Limit: 128 MB Submit: 1104 Solved: 762 [Submit][Status][Discuss]Description
设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
图片好像挂了。。。那张图是$sum_{i=1}^nsum_{j=1}^m dleft(ij
ight)$
如果没挂请忽视上面那排话
由对称性,不妨设$nle m$
有一个结论$dleft(xy
ight)=sum_{imid x}sum_{jmid y}left[gcdleft(i,j
ight)=1
ight]$
这个证明的话可以考虑每个质因数的贡献。。。意会一下
那么可以得到
$ans=sum_{x=1}^nsum_{y=1}^msum_{imid x}sum_{jmid y}left[gcdleft(i,j
ight)=1
ight]$
$=sum_{i=1}^nsum_{j=1}^mlfloorfrac{n}{i}
floorlfloorfrac{m}{j}
floorleft[gcdleft(i,j
ight)=1
ight]$
$=sum_{i=1}^nsum_{j=1}^mlfloorfrac{n}{i}
floorlfloorfrac{m}{j}
floorsum_{dmid i,dmid j}muleft(d
ight)$
$=sum_{d=1}^nmuleft(d
ight)sum_{i=1}^{lfloorfrac{n}{d}
floor}sum_{j=1}^{lfloorfrac{m}{d}
floor}lfloorfrac{n}{id}
floorlfloorfrac{m}{id}
floor$
$=sum_{d=1}^nmuleft(d
ight)sum_{i=1}^{lfloorfrac{n}{d}
floor}sum_{j=1}^{lfloorfrac{m}{d}
floor}lfloorfrac{lfloorfrac{n}{d}
floor}{i}
floorlfloorfrac{lfloorfrac{m}{d}
floor}{i}
floor$
$=sum_{d=1}^nmuleft(d
ight)left(sum_{i=1}^{lfloorfrac{n}{d}
floor}lfloorfrac{lfloorfrac{n}{d}
floor}{i}
floor
ight)left(sum_{j=1}^{lfloorfrac{m}{d}
floor}lfloorfrac{lfloorfrac{m}{d}
floor}{i}
floor
ight)$
令$gleft(n
ight)=sum_{i=1}^nlfloorfrac{n}{i}
floor$
那么$ans=sum_{d=1}^nmuleft(d
ight)gleft(lfloorfrac{n}{d}
floor
ight)gleft(lfloorfrac{m}{d}
floor
ight)$
而$g$可以通过枚举每个分子然后不停的往倍数上加$1$,然后扫一遍前缀和求出,我为了用Latex码数学公式现在已经头昏眼花神志不清,如果你觉得我已经开始胡言乱语了导致你没看懂那就看看代码吧
预处理时间复杂度为$Oleft(nlnn
ight)$
似乎神犇们都是$Oleft(n
ight)$预处理???我还是太菜了哎
每次询问的话分块求,总时间复杂度$Oleft(Tsqrt{n}
ight)$
#include <cstdio> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 50000 + 10; bool mark[maxn] = {false}; int mu[maxn], g[maxn] = {0}, sum[maxn]; int pri[maxn], prn = 0; void shai(){ mu[1] = 1; for(int i = 2; i < maxn; i++){ if(!mark[i]){ mu[i] = -1; pri[++prn] = i; } for(int j = 1; j <= prn && pri[j] * i < maxn; j++){ mark[i * pri[j]] = true; if(i % pri[j] == 0){ mu[i * pri[j]] = 0; break; } else mu[i * pri[j]] = -mu[i]; } } for(int i = 1; i < maxn; i++) for(int j = i; j < maxn; j += i) g[j]++; sum[0] = g[0] = 0; for(int i = 1; i < maxn; i++){ sum[i] = mu[i] + sum[i - 1]; g[i] += g[i - 1]; } } int main(){ shai(); int T, n, m; ll ans; scanf("%d", &T); while(T--){ scanf("%d %d", &n, &m); if(n > m) swap(n, m); ans = 0; for(int p, i = 1; i <= n; i = p + 1){ p = min(n / (n / i), m / (m / i)); ans += (ll) (sum[p] - sum[i - 1]) * g[n / p] * g[m / p]; } printf("%lld ", ans); } return 0; }