SGU - 106 The equation(扩欧+细节处理)

传送门


题目大意

给出 a x + b y + c = 0 ax+by+c=0 ax+by+c=0这一二元一次不定方程,求满足 { ( x , y ) ∣ x ∈ [ l x , r x ] , y ∈ [ l y , r y ] } \{(x,y) | x \in [lx,rx],y\in [ly,ry]\} { (x,y)x[lx,rx],y[ly,ry]}解的个数。

解题思路

自以为写了不少扩欧的题目,已经了如指掌,可是这道题又再次打脸, w a wa wa到怀疑人生…

首先不难想到如果 c c c挪到等式右边仍然是负数那么应该将 c c c变号,与此同时 a , b a,b a,b也应该变号,但是此时 a , b a,b a,b的符号可能是负的。一开始我的想法是将符号提到自变量 x , y x,y x,y处,即 ∣ a ∣ ( − x ) + ∣ b ∣ ( − y ) = c |a|(-x)+|b|(-y)=c a(x)+b(y)=c,然后求出特解后直接取负。这样的做法不可以吗?可以,但是在本题是不行的,原因如下:

因为我们要求的是在给定解空间下的解的个数,假设不考虑 a , b a,b a,b的符号那么上述方程化为 x = c − b y a x = \frac{c-by}{a} x=acby,当 a a a的符号改变后直接影响了最后的通解的形式发生改变,因此如果我们想对 a a a取负,正确的做法是对给出的解空间取反,也就是变成了 [ − r x , − l x ] [-rx,-lx] [rx,lx],对于 y y y同理。

然后就是当我们解出通解后,需要得到解的个数,因为 x , y x,y x,y的变换是相反的,看起来似乎很难下手,但是实际上我们只需要根据通解的这个不等式 l x ≤ x 0 + k 1 b g c d ( a , b ) ≤ r x lx \leq x_0+k_1\frac{b}{gcd(a,b)} \leq rx lxx0+k1gcd(a,b)brx求出 x x x在解空间下 k 1 k_1 k1的取值范围,然后和 y y y k 2 k_2 k2的取值范围,二者取一个交集即可。此时需要再次注意,左边应该向上取整,右边向下取整,画个图就明白了。

还有就是需要特判 a = 0 , b = 0 a=0,b=0 a=0,b=0的三种情况


//
// Created by Happig on 2020/10/30
//
#include <bits/stdc++.h>
#include <unordered_map>
#include <unordered_set>

using namespace std;
#define fi first
#define se second
#define pb push_back
#define ins insert
#define Vector Point
#define ENDL "\n"
#define lowbit(x) (x&(-x))
#define mkp(x, y) make_pair(x,y)
#define mem(a, x) memset(a,x,sizeof a);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<double, double> pdd;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const double dinf = 1e300;
const ll INF = 1e18;
const int Mod = 1e9 + 7;
const int maxn = 2e5 + 10;

ll exgcd(ll a, ll b, ll &x, ll &y) {
    
    
    if (!b) {
    
    
        x = 1, y = 0;
        return a;
    }
    ll d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

ll gcd(ll a, ll b) {
    
    
    return b == 0 ? a : gcd(b, a % b);
}

int main() {
    
    
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    //ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    ll a, b, c, lx, rx, ly, ry;
    cin >> a >> b >> c >> lx >> rx >> ly >> ry;
    c = -c;
    if (c < 0) c = -c, a = -a, b = -b;
    if (a < 0) a = -a, swap(lx, rx), lx = -lx, rx = -rx;
    if (b < 0) b = -b, swap(ly, ry), ly = -ly, ry = -ry;
    if (a == 0 && b == 0) {
    
    
        if (c == 0) cout << (rx - lx + 1) * (ry - ly + 1) << endl;
        else cout << 0 << endl;
        return 0;
    } else if (a == 0) {
    
    
        if (c % b == 0 && ly <= c / b && c / b <= ry) cout << rx - lx + 1 << endl;
        else cout << 0 << endl;
        return 0;
    } else if (b == 0) {
    
    
        if (c % a == 0 && lx <= c / a && c / a <= rx) cout << ry - ly + 1 << endl;
        else cout << 0 << endl;
        return 0;
    }
    ll d = gcd(a, b);
    if (c % d) {
    
    
        cout << "0" << endl;
    } else {
    
    
        ll x, y;
        exgcd(a, b, x, y);
        x = x * c / d, y = y * c / d;
        //cout << x << " " << y << endl;
        a /= d, b /= d;
        int l = max(ceil(1.0 * (lx - x) / b), ceil(1.0 * (y - ry) / a)), r = min(floor(1.0 * (rx - x) / b),
                                                                                 floor(1.0 * (y - ly) / a));
        if (r >= l) cout << r - l + 1 << endl;
        else cout << 0 << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44691917/article/details/109411788
sgu
106
今日推荐