二分,判断1-mid 有多少个数可被a,或b,或c整除。(容斥)
注意的是,当cal(mid)==n时,区间应该左移,high=mid-1;
因为cal(mid)==n时,mid可能并不是合法的数,既然1到mid有n个合法的数,那么[1,mid-1],肯定有合法的数。而比mid大的数,或许cal()它可能是n,但也是不合法的,后面有一个合法的话就是cal()=n+1了。
class Solution {
#define ll long long
public:
int a,b,c;
int gcd(int x,int y){return y?gcd(y,x%y):x;}
ll get(ll x,ll y){return x*y/gcd(x,y);}
ll get(ll x,ll y,ll z){return get(get(x,y),z);}
int cal(ll n){//1-n中有多少被a,b,c整除的正整数
ll x=get(a,b),y=get(a,c),z=get(b,c),o=get(a,b,c);
return n/a+n/b+n/c-n/x-n/y-n/z+n/o;
}
int nthUglyNumber(int n, int a, int b, int c) {
this->a=a,this->b=b,this->c=c;
int low=1,high=2000000000,mid;
while(low<=high){
mid=((ll)low+high)>>1;//low+high会爆int
int d=cal(mid);
//d=n的时候,区间应该变小。。
if(d>=n){//注意d=n的时候 比如n=4 a=2 b=3 c=4 cal(6)=4 cal(7)=4 cal(8)=5;
if(d==n&&((mid%a==0)||(mid%b==0)||(mid%c==0))) return mid;
high=mid-1;
}
else low=mid+1;
}
return -12345678912345;
}
};