POJ 2773 容斥与二分

#include <cstdio>
#include <cstring>
const int maxn = 1E6 + 10;
int p[maxn], cnt, m, k;
void init()
{
	cnt = 0;
	for (int i = 2; i * i <= m; i++)
		if (m % i == 0)
		{
			p[cnt++] = i;
			while (m % i == 0) {m /= i;}
		}
	if (m != 1) p[cnt++] = m;
}
long long cal(long long n)
{
	long long res = 0;
	for (int i = 1; i < (1 << cnt); i++)
	{
		long long bit = 0, sum = 1;
		for (int j = 0; j < cnt; j++)
			if (i & (1 << j)) bit++, sum *= p[j];
		res += (bit & 1 ? -1 : 1) * n / sum;
	}
	return n + res;
}
int main(int argc, char const *argv[])
{
	while (~scanf("%d%d", &m, &k))
	{
		init();
		long long l = 1, r = 1LL << 60, mid, tmp;
		while (r - l > 0)
		{
			mid = (l + r) >> 1;
			tmp = cal(mid);
			if (tmp >= k) r = mid;
			else l = mid + 1;
		}
		printf("%lld\n", l);
	}
	return 0;
}


求第K个与M互素的数。

数据范围超大,显然二分。

令F(x)为与M互素且小于X的数的总数,则F(x)=X-X/(1个因数) + X/(2个因数) -....;

具体实现可以使用二进制枚举子集来实现。

你可能感兴趣的:(POJ 2773 容斥与二分)