LightOJ 1306 Solutions to an Equation

给定方程 \(Ax+By+C=0\)

要求 \(x_1 \le x \le x_2\) , \(y_1 \le y \le y_2\)

求整数解的个数


\(A,B,C\) 中有 \(0\),就变成了一元一次,这个直接模拟就好

\(exgcd\)

用来求解
\[ ax+by=c \]
这类方程,且仅当 \(\gcd(a,b)|c\) 时方程有整数解

\(k=\gcd(a,b,c)\)\(k>1\),那就把 \(a,b,c\) 都除以 \(k\) ,让 \(c=\gcd(a,b)\)
\[ ax+by=\gcd(a,b) \]
\(a_1=b,b_1=a\%b\),即 \(b_1=a-\lfloor \frac ab \rfloor \times b\)

\(\gcd(a,b)=\gcd(a_1,b_1)\)

所以(这里用 \(x_1,y_1\) 代表另一组解)
\[ a_1 \times x_1+b_1 \times y_1=\gcd(a_1,b_1)=\gcd(a,b) \]

\[ b \times x_1+(a-\lfloor \frac ab \rfloor*b) \times y_1=\gcd(a,b) \]

\[ b \times x_1+a \times y_1-\lfloor \frac ab \rfloor \times b \times y_1=\gcd(a,b) \]

\[ b \times x_1-b \times \lfloor \frac ab \rfloor \times y_1+a \times y_1=\gcd(a,b) \]

\[ b \times (x_1-\lfloor \frac ab \rfloor \times y_1)+a \times y_1=\gcd(a,b) \]

\[ a \times y_1+b \times (x_1-\lfloor \frac ab \rfloor \times y_1)=\gcd(a,b) \]

于是得出了
\[ \left\{ \begin{aligned} a \times y_1 & +b \times (x_1-\lfloor \frac ab \rfloor \times y_1)&=\gcd(a,b)\\ a \times x & +b \times y&=\gcd(a,b) \end{aligned} \right. \]
对比一下就发现了
\[ \left\{ \begin{aligned} x&=y_1\\ y&=x_1-\lfloor \frac ab \rfloor \times y_1 \end{aligned} \right. \]
这就可以像 \(\gcd\) 一样递归做了

当递归到 \(b=0\) 的时候,就有特解了
\[ ax+by=\gcd(a,b) \]
我们知道 \(\gcd\) 递归到 \(b=0\) 的时候返回的是 \(a\)

于是把 \(\gcd(a,b)\) 换成 \(a\)
\[ ax+by=a \]
因为 \(b=0\)
\[ ax=a \]
于是得出特解 \(x=1,y=0\) ,其实 \(y\) 可以随便选但是要防止答案爆掉

然后就是模拟了

时间复杂度 \(O(T\log1e8)\)

// This code writed by chtholly_micromaker(MicroMaker)
#include <bits/stdc++.h>
#define reg register
#define int long long
using namespace std;
template <class t> inline void read(t &s)
{
    s=0;
    reg int f=1;
    reg char c=getchar();
    while(!isdigit(c))
    {
        if(c=='-')
            f=-1;
        c=getchar();
    }
    while(isdigit(c))
        s=(s<<3)+(s<<1)+(c^48),c=getchar();
    s*=f;
    return;
}
inline int exgcd(int a,int b,int &x,int &y)
{
    if(!b)
    {
        x=1,y=0;
        return a;
    }
    reg int c=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return c;
}
inline void work()
{
    reg int A,B,C,xs,xt,ys,yt;
    read(A);read(B);read(C);read(xs);read(xt);read(ys);read(yt);
    if(!A&&!B)
    {
        if(!C)
            printf("%lld\n",(yt-ys+1)*(xt-xs+1));
        else
            puts("0");
        return;
    }
    if(!A)
    {
        if(C%B)
        {
            puts("0");
            return;
        }
        if(ys<=-C/B&&-C/B<=yt)
            printf("%lld\n",xt-xs+1);
        else
            puts("0");
        return;
    }
    if(!B)
    {
        if(C%A)
        {
            puts("0");
            return;
        }
        if(xs<=-C/A&&-C/A<=xt)
            printf("%lld\n",yt-ys+1);
        else
            puts("0");
        return;
    }
    C*=-1ll;
    if(A<0)
    {
        A*=-1ll;
        swap(xs,xt);
        xs*=-1ll;
        xt*=-1ll;
    }
    if(B<0)
    {
        B*=-1ll;
        swap(ys,yt);
        ys*=-1ll;
        yt*=-1ll;
    }
    reg int x0,y0;
    reg int g=__gcd(A,B);
    if(C%g)
    {
        puts("0");
        return;
    }
    exgcd(A,B,x0,y0);
    A/=g;B/=g;
    x0=C/g*x0;y0=C/g*y0;
    reg double xL=(double)(xs-x0)/B;
    reg double xR=(double)(xt-x0)/B;
    reg double yL=(double)(y0-yt)/A;
    reg double yR=(double)(y0-ys)/A;
    // if(xL>xR)
        // swap(xL,xR);
    // if(yL>yR)
        // swap(yL,yR);
    reg int solL=max(ceil(xL),ceil(yL));
    reg int solR=min(floor(xR),floor(yR));
    // printf("x0 %lld  y0 %lld\n",x0,y0);
    // printf("xt %lld %lld\n",(int)ceil(xL),(int)floor(xR));
    // printf("yt %lld %lld\n",(int)ceil(yL),(int)floor(yR));
    printf("%lld\n",max(0ll,solR-solL+1));
    return;
}
signed main(void)
{
    int T;cin>>T;
    for(int i=1;i<=T;++i)
        printf("Case %lld: ",i),work();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/chinesepikaync/p/12305653.html