HDU3388 Coprime(二分 + 容斥)

题意
给你 n , m n,m ,让你找到第 k k 个与 n n m m 互素的数。
思路:
范围比较大,我们可以先找出 n n m m 的质因子,然后二分答案。每次容斥判定 m i d mid 是第几个与 n n m m 互质的数字。

#include <iostream>
#include <cstring>
#include <queue>
#include <cmath>
#include <map>
#include <stack>
#include <cstdio>
#include <sstream>
#include <algorithm>

using namespace std;
#define read(x) scanf("%d", &x)
#define Read(x, y) scanf("%d%d", &x, &y)
#define gc(x) scanf(" %c", &x);
#define mmt(x, y) memset(x, y, sizeof x)
#define write(x) printf("%d\n", x)
#define INF 0x3f3f3f3f
#define ll long long
#define mod 998244353
const ll N = 1e5 + 5;
ll prime[N];
int idx = 0;
ll ok(ll n)
{
	ll s = (1 << idx);
	ll ans = 0;
	for (ll i = 1; i < s; ++i)
	{
		int cnt = 0;
		ll p = 1;
		for (ll j = 0; j < idx; ++j)
		{
			if ((i >> j) & 1)
			{
				cnt++;
				p *= prime[j + 1];
			}
		}
		if (cnt & 1) ans += n / p;
		else ans -= n / p;
	}
	return n - ans;
}
int main()
{
	int t;
	read(t);
	for(int Case = 1;Case <= t;++Case)
	{
		idx = 0;
		ll m, n, k;
		scanf("%lld%lld%lld",&m,&n,&k);

		for (ll i = 2; i * i <= m; i++)//分解质因子
		{
			if (!(m % i))
			{
				prime[++idx] = i;
				while (!(m % i))
					m /= i;
			}
		}
		if (m > 1)
			prime[++idx] = m;
		for (ll i = 2; i * i <= n; ++i)
		{
			if (!(n % i))
			{
				prime[++idx] = i;
				while (!(n % i))
					n /= i;
			}
		}
		if (n > 1)
			prime[++idx] = n;
		ll l = 1, r = 1e14;

		sort(prime + 1, prime + idx + 1);
		int p = unique(prime + 1, prime + idx + 1) - prime - 1;
		idx = p;
		
		while (l < r)//二分答案
		{
			ll mid = l + r >> 1;
			ll ans = ok(mid);
			if (ans >= k)
				r = mid;
			else
				l = mid + 1;
		}
		printf("Case %d: %lld\n",Case,r);
	}
}
发布了632 篇原创文章 · 获赞 27 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_43408238/article/details/104056889