CF1182F Maximum Sine

最大化 (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;
}
原文地址:https://www.cnblogs.com/lhm-/p/13843467.html