一开始以为是线性规划的题目,看了网上的提示说是求模线性方程。用拓展欧几里得算法可以得出原方程的一个解。然后就可以根据这个解判断在所给的区间里有几个解。题目比较纠结的地方是边界问题的判断,花了很多时间。以后要多做题才能更快地考虑好边界问题。
由ax+by+c = 0有ax+by = -c,两边取模b得到
ax+by ≡ -c (mod b) 推出 ax ≡ -c (mod b)
模线性方程有解当且仅当gcd(a,b) | -c,有解的情况下方程对模-c有d个不同的解,d=gcd(a,b)
根据拓展欧几里得算法可以算出x0, y0使得d = a*x0+b*y0
则x = x0*(-c/d), y = y0*(-c/d)为原方程ax+by+c=0的一个解
则方程的所有解为x = x0*(-c/d) + i*(b/d), y = y0*(-c/d) - i*(a/d)
计算所有的i使得解在所给区间内的个数即可。
#include <stdio.h>
typedef struct tagNode {
long long d; long long x; long long y;
} Node;
void swap(long long* a, long long* b) {
long long t = *a;
*a = *b;
*b = t;
}
Node euclid(long long a, long long b) {
Node t;
if (!b) {
t.d = a; t.x = 1; t.y = 0;
return t;
}
t = euclid(b, a % b);
Node t1;
t1.d = t.d; t1.x = t.y; t1.y = t.x-(a/b)*t.y;
return t1;
}
int main(void) {
long long a, b, c;
long long x1, x2, y1, y2;
scanf ("%I64d%I64d%I64d", &a, &b, &c);
c = -c;
scanf ("%I64d%I64d%I64d%I64d", &x1, &x2, &y1, &y2);
long long count = 0;
if (a==0 && b==0) {
if (c==0) {
count = (x2-x1+1)*(y2-y1+1);
}
} else if (a==0) {
if (c%b==0 && c/b>=y1 && c/b<=y2) {
count = x2-x1+1;
}
} else if (b==0) {
if (c%a==0 && c/a>=x1 && c/a<=x2) {
count = y2-y1+1;
}
} else { //如果a,b都不为0,用拓展欧几里得算出一个解
Node t = euclid(a, b);
if (c % t.d == 0) {
t.x *= c/t.d;
t.y *= c/t.d;
long long lx, rx, ly, ry;
lx = (x1<=t.x || (x1-t.x)*t.d%b==0) ? (x1-t.x)*t.d/b : (x1-t.x)*t.d/b+1;
rx = (x2>=t.x || (t.x-x2)*t.d%b==0) ? (x2-t.x)*t.d/b : (x2-t.x)*t.d/b-1;
ly = (y1<=t.y || (y1-t.y)*t.d%a==0) ? (t.y-y1)*t.d/a : (t.y-y1)*t.d/a-1;
ry = (y2>=t.y || (t.y-y2)*t.d%a==0) ? (t.y-y2)*t.d/a : (t.y-y2)*t.d/a+1;
if (lx > rx) {
swap(&lx, &rx);
}
if (ly > ry) {
swap(&ly, &ry);
}
if (lx <= ry && ly <= rx) { //求出两个区间交集的元素个数
long long max = (lx>ly) ? lx : ly;
long long min = (rx<ry) ? rx : ry;
count = min-max+1;
}
}
}
printf ("%I64d\n", count);
return 0;
}