题解:
$ans = sum_{x = 1}^{n}sum_{y = 1}^{m}sum_{i = 1}^{k}[gcd(x, y) == p_{i}]$其中k为质数个数
$$ans = sum_{i = 1}^{k}sum_{x = 1}^{n}sum_{y = 1}^{m}[gcd(x, y) == p_{i}]$$
设$f(d)$表示$x$从$1$到$n$,$y$从$1$到$m$,$gcd == d$的个数,$g(d)$表示相同条件下$d | gcd$(即$gcd$为$d$的倍数)的个数
那么$$f(d) = sum_{x = 1}^{n}sum_{y = 1}^{m}[gcd(x, y) == d]$$,$$g(d) = lfloor{frac{n}{d}}
floorlfloor{frac{m}{d}}
floor$$
因为$$g(x) = sum_{x|d}^{min(n, m)}f(d)$$
所以反演一下。
$$f(x) = sum_{x | d}^{min(n, m)}mu(frac{d}{x})g(d)$$
那么$ans = sum_{i = 1}^{k}f(p_{i})$
$$= sum_{i = 1}^{k}sum_{x | d}^{min(n, m)}mu(frac{d}{x})g(d)$$
改成直接枚举系数
$$= sum_{i = 1}^{k}sum_{d = 1}^{lfloor{frac{min(n, m)}{p_{i}}}
floor}mu(d)g(dp_{i})$$
$$= sum_{i = 1}^{k}sum_{d = 1}^{lfloor{frac{min(n, m)}{p_{i}}}
floor}mu(d)lfloor{frac{n}{dp_{i}}
floor lfloor{frac{m}{dp_{i}}
floor}}$$<---枚举每个$mu(d)分别被每个质数统计了几次$
$$= sum_{T = 1}^{min(n, m)} lfloor{frac{n}{T}}
floor lfloor{frac{m}{T}}
floorsum_{k|T}{mu(frac{T}{k})}$$<---枚举每个$lfloor{frac{n}{T}}
floor lfloor{frac{m}{T}}
floor$会给哪些$mu$做贡献(哪些$mu$会在某次被统计$lfloor{frac{n}{T}}
floor lfloor{frac{m}{T}}
floor$次)
然后暴力枚举质数和系数,给对应的$mu$做贡献(质数$p_{i}$给它的倍数做贡献),统计前缀和,对前面的$lfloor{frac{n}{T}}
floor lfloor{frac{m}{T}}
floor$进行整数分块处理
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define R register int 4 #define AC 10000100 5 #define LL long long 6 int n, m, tot, t; 7 int prime[AC], mu[AC]; 8 LL s[AC], ans; 9 bool z[AC]; 10 11 inline int read() 12 { 13 int x = 0;char c = getchar(); 14 while(c > '9' || c < '0') c = getchar(); 15 while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); 16 return x; 17 } 18 19 void pre() 20 { 21 int now; 22 mu[1] = 1; 23 for(R i = 2; i <= 10000000; i++) 24 { 25 if(!z[i]) prime[++tot] = i, mu[i] = -1; 26 for(R j = 1; j <= tot; j++) 27 { 28 now = prime[j]; 29 if(i * now > 10000000) break; 30 z[i * now] = true; 31 if(!(i % now)) break; 32 mu[now * i] = -mu[i]; 33 } 34 } 35 int p; 36 for(R i = 1; i <= tot; i++)//枚举质数 37 { 38 p = prime[i];//卡常 39 for(R j = p; j <= 10000000; j += p) //枚举倍数 40 s[j] += mu[j / p];//or j = 系数, s[j * prime[i]] += mu[j]; 41 } 42 for(R i = 1; i <= 10000000; i++) s[i] += s[i - 1]; 43 } 44 45 void work() 46 { 47 t = read(); 48 while(t--) 49 { 50 int pos = 0; 51 ans = 0; 52 n = read(), m = read(); 53 int b = min(n, m);//这里要取min!!! 54 for(R i = 1; i <= b; i = pos + 1) 55 { 56 pos = min(n / (n / i), m / (m / i)); 57 ans += (LL) (n / i) * (LL) (m / i) * (LL) (s[pos] - s[i - 1]);//error 只有ans是LL是不够的 58 } 59 printf("%lld ", ans); 60 } 61 } 62 63 int main() 64 { 65 // freopen("in.in", "r", stdin); 66 //freopen("YYnoGCD.in", "r", stdin); 67 //freopen("YYnoGCD.out", "w", stdout); 68 pre(); 69 work(); 70 //fclose(stdin); 71 //fclose(stdout); 72 return 0; 73 }