题意
有(T)组询问,每次询问求
[sumlimits_{x=1}^{a}sumlimits_{y=1}^{b}[gcd(x,y)=d]
]
思路
因为我不喜欢用(x、y、a、b、d),所以一一对应换成(i、j、n、m、k)
直接淦式子
[egin{align*}&sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}[gcd(i,j)=k]\=& sumlimits_{i=1}^{lfloor frac nk
floor}sumlimits_{j=1}^{lfloorfrac mk
floor}[gcd(i,j)=1]\=&sumlimits_{i=1}^{lfloor frac nk
floor}sumlimits_{j=1}^{lfloorfrac mk
floor}sumlimits_{d|gcd(i,j)}mu(d)\=&sumlimits_{i=1}^{lfloor frac nk
floor}sumlimits_{j=1}^{lfloorfrac mk
floor}sumlimits_{d|i}sum _{d|j}mu(d)\=&sumlimits_{d=1}^{min(lfloorfrac nk
floor,lfloorfrac mk
floor)}mu(d)sumlimits_{i=1}^{lfloor frac nk
floor}sumlimits_{j=1}^{lfloorfrac mk
floor}sumlimits_{d|i}sumlimits_{d|j}1\=&sumlimits_{d=1}^{min(lfloorfrac nk
floor,lfloorfrac mk
floor)}mu(d)sumlimits_{i=1}^{lfloor frac nk
floor}sumlimits_{d|i}1sumlimits_{j=1}^{lfloorfrac mk
floor}sumlimits_{d|j}1\=&sumlimits_{d=1}^{min(lfloorfrac nk
floor,lfloorfrac mk
floor)}mu(d)lfloorfrac{lfloor frac nk
floor}d
floorlfloorlfloorfrac{frac mk
floor}d
floor\=&sumlimits_{d=1}^{min(lfloorfrac nk
floor,lfloorfrac mk
floor)}mu(d)lfloorfrac n{kd}
floorlfloorfrac m{kd}
floorend{align*}
]
现在就可以每次询问(O(n))做这道题了
但是跑不过啊,不过显然可以数论分块,所以我们就可以(O(sqrt n))回答每次询问了
代码
/*
Author:loceaner
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 5e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, k, mu[A], p[A], sum[A], cnt;
bool vis[A];
void getmu(int n) {
mu[1] = 1;
for (int i = 2; i <= n; i++) {
if (!vis[i]) p[++cnt] = i, mu[i] = -1;
for (int j = 1; j <= cnt && i * p[j] <= n; j++) {
vis[i * p[j]] = 1;
if (i % p[j] == 0) break;
mu[i * p[j]] -= mu[i];
}
}
for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + mu[i];
}
int solve(int n, int m, int k) {
int ans = 0, maxn = min(n, m);
for (int l = 1, r; l <= maxn; l = r + 1) {
r = min(n / (n / l), m / (m / l));
ans += (sum[r] - sum[l - 1]) * (n / (k * l)) * (m / (k * l));
}
return ans;
}
int main() {
getmu(50000);
int T = read();
while (T--) {
n = read(), m = read(), k = read();
cout << solve(n, m, k) << '
';
}
return 0;
}