零、欸嘿!
英雄哪里出来《C语言入门100例》传送门
https://bbs.csdn.net/forums/hero?category=0&typeId=17913https://bbs.csdn.net/forums/hero?category=0&typeId=17913
一、题目
1201. 丑数 III
难度中等86
给你四个整数:n ?、a ?、b ?、c ?,请你设计一个算法来找出第?n ?个丑数。
丑数是可以被?a ?或?b ?或?c ?整除的?正整数?。
示例 1:
输入:n = 3, a = 2, b = 3, c = 5
输出:4
解释:丑数序列为 2, 3, 4, 5, 6, 8, 9, 10... 其中第 3 个是 4。
二、解题
思路;摊牌了,我抄的,但是我看懂了(大概),就是好好看看容斥原理,a,b,c,的丑数并集,然后a的丑数就是1a,2a,3a等等,所以小于等于3a的丑数有(3a/a)等于3个,所以?小于mid的丑数个数m = mid/a+mid/b+mid/c-mid/ab-mid/ac-mid/bc+mid/abc,除不尽的情况也没事,根据循环条件,最后一定会确定一个数,除不尽时候会继续循环下去
#define ll long long //求最大公约数
int gcd(int a, int b){
return !b ? a : gcd(b, a % b);
}
ll lcm(int a, int b){
return (ll)a / gcd(a, b) * b; //求最小公倍数
}
int nthUglyNumber(int n, int a, int b, int c){
ll ab = lcm(a, b); //a 和 b的最小共倍数
ll ac = lcm(a, c); //a 和 c 的最小共倍数
ll bc = lcm(b, c); //b 和 c 的最小公倍数
ll abc = lcm(lcm(a, b), c); //a, b, c的最小公倍数
int left = 1, right = 2000000000; //二分左右端点
while(left < right){ //退出循环的条件,最后可以唯一确定一个数
ll mid = left + (right - left) / 2; //中点
ll m = mid/a+mid/b+mid/c-mid/ab-mid/ac-mid/bc+mid/abc; //小于mid的丑数个数
if(m < n){
left = mid + 1; //重新确定左右边界,继续循环
}
else{
right = mid;
}
}
return left; //返回左端点
}
三、结果
?
|