#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 100;
int n, tot, m;
int prime[maxn], mu[maxn];
bool vis[maxn];
void Mobius() //筛莫比乌斯函数
{
tot = 0;
mu[1] = 1;
memset(vis, false, sizeof(vis));
for(int i = 2; i < maxn; ++ i)
{
if(!vis[i])
{
prime[tot++] = i;
mu[i] = -1;
}
for(int j = 0; j < tot && i * prime[j] < maxn; ++ j)
{
vis[i * prime[j]] = true;
if(i % prime[j] == 0)
{
mu[i * prime[j]] = 0;
break;
}
else
{
mu[i * prime[j]] = -mu[i];
}
}
}
}
ll get(ll a, ll b)
{
ll ans = 0;
for(int i = 1; i <= min(a, b); ++ i)
{
ans += mu[i] * (a / i) * (b / i);
}
return ans;
}
int main()
{
//freopen("in.txt", "r", stdin);
Mobius();
int t;
cin >> t;
while(t --)
{
cin >> m >> n;
cout << get(n, m) << endl;
}
return 0;
}
进阶:求[a, b] 和 [c, d]区间gcd(x, y) == 1 的数量,与上面的区别就在于要先求[1, b], [1, d]符合条件的数目,然后再用容斥处理一下多算的情况。
主函数应该改成这样,其余的不用变:
int main()
{
Mubius();
ll a, b, c, d;
cin >> a >> b >> c >> d;
ll ans = get(b, d); //先求出[1, b] 和 [1, d]的。
ans -= get(a - 1, d); //再减去不符合的
ans -= get(c - 1, b);
ans += get(a - 1, c - 1); //再加上重复减去的
cout << ans << endl;
return 0;
}
//个过程也就是一个容斥定理