前言
题难,只做一个题打个卡(滑稽)
概念
图片参考自:《算法零基础100讲》(第29讲) 容斥原理
作者:英雄哪里出来
两个集合的并
集合A和集合B并集的元素个数,等于A中元素加B中元素,再减去 A交B的元素。
三个集合的并
同理:三个集合A、B、C的并集就是A中元素个数加B元素个数加C元素个数,再减去交集。
图示:
公式表示为:
1201. 丑数 III
原题链接:1201. 丑数 III
分析
根据上面的概念可知
num范围内的丑数数量为:
num/a + num/b + num/c - num/lcm(ab) - num/lcm(ac) - num/lcm(bc) + num/lcm(abc)
lcm为最小公倍数
实现如下:
#define ll long long
int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a % b);
}
ll lcm(int a, int b)
{
return (ll)a / gcd(a, b) * b;
}
代码
class Solution {
private:
#define ll long long
#define MAX 2000000000
int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a % b);
}
ll lcm(int a, int b)
{
return (ll)a / gcd(a, b) * b;
}
int Min_Int(int x, int y)
{
return x < y ? x : y;
}
public:
int nthUglyNumber(int n, int a, int b, int c)
{
if (a == 0 || b == 0 || c == 0)
return 0;
ll ab = lcm(a, b);
ll ac = lcm(a, c);
ll bc = lcm(b, c);
ll abc = lcm(ab, c);
int left = Min_Int(a, Min_Int(b, c));
int right = MAX;
while (left < right)
{
ll mid = left + (right - left) / 2;
if ((mid / a + mid / b + mid / c - mid / ab - mid / ac - mid / bc + mid / abc) < n)
{
left = mid + 1;
}
else
{
right = mid;
}
}
return left;
}
};