给定x属于[1, a] 和y属于[1, b],求gcd(x, y) == 1的(x, y)的数量(莫比乌斯函数)

#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;
}
//个过程也就是一个容斥定理

猜你喜欢

转载自blog.csdn.net/aqa2037299560/article/details/85206054
今日推荐