题意大概就是要求$2p mod 2q$距离$q$最近。
为了方便,我们把$p$和$q$同时乘2
我们可以二分一个$y$。
那么就是询问$px mod q$在$[frac{q}{2}-y,frac{q}{2}+y]$上是否有取值。
令$l=frac{q}{2}-y,r=frac{q}{2}+y$
等价于询问$sum_{x=a}^{b} lfloor frac{px+q-l}{q} floor - lfloor frac{px+q-r-1}{q} floor$是否大于0
使用类欧即可解决。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 inline LL Euc(LL n, int a, int b, int c) { 5 if(n == -1) return 0; 6 if(a == 0) return 1ll * (b / c) * (n + 1); 7 if(a >= c || b >= c) { 8 return 1ll * n * (n + 1) / 2 * (a / c) + 1ll * (n + 1) * (b / c) + Euc(n, a % c, b % c, c); 9 } 10 LL m = (1ll * a * n + b) / c; 11 return 1ll * n * m - Euc(m - 1, c, c - b - 1, a); 12 } 13 inline LL get_ab(int A, int B, int a, int b, int c) { 14 return Euc(B, a, b, c) - Euc(A - 1, a, b, c); 15 } 16 inline bool check(int a, int b, int p, int q, int mid) { 17 int l = q / 2 - mid, r = q / 2 + mid; 18 LL res = get_ab(a, b, p, q - l, q) - get_ab(a, b, p, q - r - 1, q); 19 if(res) return true; 20 return false; 21 } 22 inline void exgcd(int p, int q, LL &x, LL &y) { 23 if(q == 0) { 24 x = 1, y = 0; 25 return; 26 } 27 exgcd(q, p % q, y, x); 28 y -= 1ll * (p / q) * x; 29 } 30 inline LL Do(int p, int q, int a, int b, int t) { 31 int GCD = __gcd(p, q); 32 if(t % GCD != 0) return 1e18; 33 p /= GCD, q /= GCD, t /= GCD; 34 LL x, y; 35 exgcd(p, q, x, y); 36 x *= t, y *= t; 37 x += 1ll * (a - x) / q * q; 38 while(x < a) x += q; 39 while(x - q >= a) x -= q; 40 if(x > b) return 1e18; 41 return x; 42 } 43 inline void solve() { 44 int a, b, p, q; 45 scanf("%d%d%d%d", &a, &b, &p, &q); 46 p *= 2; q *= 2; 47 int l = 0, r = q / 2, t = 0; 48 while(l <= r) { 49 int mid = (l + r) / 2; 50 if(check(a, b, p, q, mid)) r = (t = mid) - 1; 51 else l = mid + 1; 52 } 53 printf("%lld ", min(Do(p, q, a, b, q / 2 - t), Do(p, q, a, b, q / 2 + t))); 54 } 55 int main() { 56 int T; 57 scanf("%d", &T); 58 while(T --) { 59 solve(); 60 } 61 }