题意 求不定方程 ax + by + c = 0 满足 x1 <= x <= x2, y1 <= y <= y2 的解的个数
这里弱先来预习一下扩展欧几里得算法 ( O_O )
欧几里得算法
简单的证明
令 a%b = r 设 d 是 a, b 的公约数即d|a && d|b
又 d'r = a – kb 所以 r|d 即 a, b 的公约数都是 b, r 的公约数
设 d' 是 b, r 的公约数即 d'|b && d'|r
又 a = kb + r 所以 d'|a 即 b, r 的公约数都是 a, b 的公约数
所以 gcd(a, b) = gcd(b, a%b);
欧几里得算法的代码
int gcd(int a, int b)
{
if(b == 0) return a;
return gcd(b, a % b);
}
扩展欧几里得算法
对于二整数 a 、b,必存在整数 x 、 y 使得 ax + by = gcd(a, b),可以通过扩展欧几里得算法求出一组满足的x、y。
简单的证明
设 a*x1 + b*y1 = gcd(a, b) (1)
b*x2 + a%b * y2 = gcd(b, a%b)(2)
又 gcd(a,b) = gcd(b,a%b)
所以有a*x1 + b*y1 = b*x2 + (a - a/b * b)*y2 (此处的 '/' 为向下取整除)
化简有a*x1 + b*y1 = a*y2 + b* (x2 – a/b * y2)
那么有x1 = y2, y1 = x2 – a/b * y2;
所以我们可以通过方程(2)的一组解得到方程(1)的一组解
这样递归下去类似辗转相除法 可以发现最后总可以递归到 方程 a*x + 0*y = gcd(a, 0) (3)
而方程(3)的一组解为 x = 1, y = 0
那么我们在递归求 gcd(a,b) 的过程中就可以一起求出方程 a*x + b*y = gcd(a, b) 的一组解
扩展欧几里得算法的代码
ll exGcd(ll a, ll b, ll &x, ll &y)
{
if(b == 0)
{
x = 1, y = 0;
return a;
}
ll ret = exGcd(b, a % b, x, y), t = x;
x = y, y = t - a / b * y;
return ret;
}
不定方程 ax + by = c 的整数通解
通过扩展欧几里得算法得到 ax + by = gcd(a, b)的一组整数解后 如何得到不定方程 ax + by = c 的整数通解呢
令 d = gcd(a,b) 只有 d | c 时这个方程才存在整数解
我们可以通过扩展欧几里得算法求得方程 ax + by = d 的一组整数解 x0, y0 方程两边同时乘上 c/d 就可以得到方程 ax + by = c 的一组整数解x = x0 * c/d, y = y0 * c/d
现在我们知道了ax + by = c 的一组整数解 又怎样得到他的所有整数解呢
设 x+x' , y+y'为下一组整数解 即 a*(x + x’) + b*(y + y’) = c
那么必须满足 ax' +by' = 0 且 x' 是满足的最小的正整数
ax' + by' = 0 --> y' = -((a/d) / (b/d))x'
即 x' 的最小正整数解为 x' = b/d , y' = -a/d
那么原不定方程的通解为 {(x + b/d * k , y - a/d * k) | k in Z}
SGU106 The equation
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const double eps = 1e-8;
typedef long long ll;
ll exGcd(ll a, ll b, ll &x, ll &y)
{
if(b == 0)
{
x = 1, y = 0;
return a;
}
ll ret = exGcd(b, a % b, x, y), t = x;
x = y, y = t - a / b * y;
return ret;
}
int main()
{
ll a, b, c, d, x, y;
ll x1, y1, x2, y2, t;
while(~scanf("%lld%lld%lld", &a, &b, &c))
{
c = -c;
ll ans = 0;
scanf("%lld%lld%lld%lld", &x1, &x2, &y1, &y2);
d = exGcd(a, b, x, y);
if(d == 0) // a == 0 && b == 0
ans = c ? 0 : (x2 - x1 + 1) * (y2 - y1 + 1);
else if(c % d == 0) // ax + by = c
{
double lx, rx, ly, ry, l, r;
x = c / d * x, y = c / d * y;
if(a == 0) //0x + by = c
ans = (x2 - x1 + 1) * (y1 <= y && y <= y2);
else if(b == 0) //ax + 0y = c
ans = (y2 - y1 + 1) * (x1 <= x && x <= x2);
else //ax + by = c
{
lx = 1.0 * (x1 - x) * d / b;
rx = 1.0 * (x2 - x) * d / b;
if(lx > rx) swap(lx, rx);
ly = 1.0 * (y - y1) * d / a;
ry = 1.0 * (y - y2) * d / a;
if(ly > ry) swap(ly, ry);
l = ceil(max(lx, ly) - eps);
r = floor(min(rx, ry) + eps);
ans = max(0.0, r - l + 1);
}
}
printf("%lld\n", ans);
}
return 0;
}
SGU 106 The equation
There is an equation ax + by + c = 0. Given a,b,c,x1,x2,y1,y2 you must determine, how many integer roots of this equation are satisfy to the following conditions : x1<=x<=x2, y1<=y<=y2. Integer root of this equation is a pair of integer numbers (x,y).
Input
Input contains integer numbers a,b,c,x1,x2,y1,y2 delimited by spaces and line breaks. All numbers are not greater than 108 by absolute value.
Output
Write answer to the output.
Sample Input
1 1 -3 0 4 0 4
Sample Output
4