最大化 (f(x)=left|sinleft(frac{p}{q}pi x ight) ight|) 就是让 (frac{px}{q}) 越接近 (frac{1}{2}+k),即 (frac{px}{q}) 的小数部分 (frac{px mod q}{q}) 越接近 (frac{1}{2})。
转化后为使 (|2px mod 2q -q|) 最小,二分该值 (v),设 (l=q-v,r=q+v),得判定 (2px mod 2q) 是否在区间 ([l,r]) 内,有个结论:
[large [2px mod 2q in[l,r]]=leftlfloor frac{2px-l}{2q}
ight
floor-leftlfloor frac{2px-r-1}{2q}
ight
floor
]
因此,得:
[large exist x in [a,b],2px mod 2q in[l,r] Leftrightarrow sum_{x=a}^b left( leftlfloor frac{2px-l}{2q}
ight
floor-leftlfloor frac{2px-r-1}{2q}
ight
floor
ight)>0
]
和式用类欧计算,二分后用扩欧解同余方程即可求出 (x)。
#include<bits/stdc++.h>
#define inf 1000000000000000000
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int T;
ll a,b,p,q,l,r,ans;
ll f(ll n,ll a,ll b,ll c)
{
if(n<0) return 0;
if(!a) return (n+1)*(b/c);
if(a>=c||b>=c) return (n+1)*n/2*(a/c)+(n+1)*(b/c)+f(n,a%c,b%c,c);
ll m=(n*a+b)/c;
return n*m-f(m-1,c,c-b-1,a);
}
bool check(ll v)
{
ll l=q/2-v,r=q/2+v,v1,v2;
return f(b,p,q-l,q)-f(a-1,p,q-l,q)-f(b,p,q-r-1,q)+f(a-1,p,q-r-1,q);
}
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
void exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b) x=1,y=0;
else exgcd(b,a%b,y,x),y-=a/b*x;
}
ll calc(ll p,ll q,ll a,ll b,ll v)
{
ll g=gcd(p,q),x,y;
if(v%g) return inf;
p/=g,q/=g,exgcd(p,q,x,y);
x*=v/g,x+=(a-x)/q*q;
while(x<a) x+=q;
while(x-q>=a) x-=q;
if(x>b) return inf;
}
int main()
{
read(T);
while(T--)
{
read(a),read(b),read(p),read(q),l=ans=0,r=q,p*=2,q*=2;
while(l<=r)
{
ll mid=(l+r)>>1;
if(check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%lld
",min(calc(p,q,a,b,q/2-ans),calc(p,q,a,b,q/2+ans)));
}
return 0;
}