題目鏈接
題意:給定兩個點,構成一條線段,這些點都是十分位形式的,求落在這個直線上的正數點。
思路:先把直線表達成a x + b y = c的形式,a,b, c都化為整數表示,然後利用擴展gcd求出x和y的通解,然後已知min(x1, x2) <= x <= max(x1, x2), min(y1, y2) <= y <= max(y1, y2),這樣一來就可以求出通解中t的范圍,t能取的整數就是整數解,就得到答案。
值得注意的是,直線為平行坐標系的情況,要特殊判斷一下
代碼:
#include#include #include #include using namespace std; const long long INF = 0x3f3f3f3f3f3f3f; int t; long long xx1, yy1, xx2, yy2; long long a, b, c; long long read(){ double t; scanf("%lf", &t); return (long long)(10 * (t + 0.05)); } long long gcd(long long a, long long b) { if (!b) return a; return gcd(b, a % b); } long long exgcd(long long a, long long b, long long &x, long long &y) { if (!b) {x = 1; y = 0; return a;} long long d = exgcd(b, a % b, y, x); y -= a / b * x; return d; } void build() { a = (yy2 - yy1) * 10; b = (xx1 - xx2) * 10; c = (yy2 - yy1) * xx1 + (xx1 - xx2) * yy1; long long t = gcd(gcd(a, b), c); a /= t; b /= t; c /= t; } long long solve() { long long ans = 0; long long x, y; long long d = exgcd(a, b, x, y); long long up = INF, down = -INF; if (xx1 > xx2) swap(xx1, xx2); if (yy1 > yy2) swap(yy1, yy2); if (c % d) return ans; if (b / d > 0) { down = max(down, (long long)ceil((xx1 * d * 1.0 / 10 - x * c * 1.0) / b)); up = min(up, (long long)floor((xx2 * d * 1.0 / 10 - x * c * 1.0) / b)); } else if (b / d < 0) { up = min(up, (long long)floor((xx1 * d * 1.0 / 10 - x * c * 1.0) / b)); down = max(down, (long long)ceil((xx2 * d * 1.0 / 10 - x * c * 1.0) / b)); } else if (xx1 % 10) return ans; if (a / d > 0) { down = max(down, (long long)ceil((y * c * 1.0 - d * yy2 * 1.0 / 10) / a)); up = min(up, (long long)floor((y * c * 1.0 - d * yy1 * 1.0 / 10) / a)); } else if (a / d < 0) { up = min(up, (long long)floor((y * c * 1.0 - d * yy2 * 1.0 / 10) / a)); down = max(down, (long long)ceil((y * c * 1.0 - d * yy1 * 1.0 / 10) / a)); } else if (yy1 % 10) return ans; if (down <= up) ans += up - down + 1; return ans; } int main() { scanf("%d", &t); while (t--) { xx1 = read(); yy1 = read(); xx2 = read(); yy2 = read(); build(); printf("%lld\n", solve()); } return 0; }