cqyz oj | 解的个数 | Exgcd
Description
已知x,y满足如下条件:
ax+by+c=0 ; x1 <= x <= x2 ; y1 <= y <= y2 ; x,y均为整数。
其中:a,b,c,x1,x2,y1,y2 都是绝对值不超过 10^8 的整数。
求(x,y)的解的个数。
Input
第一行:n 说明:有 n 个任务。n<=10。之后有 n 行,每行为:a,b,c,x1,x2,y1,y2
Output
有n行,第i行是第i个任务的结果。
Sample Input 1
2 2 3 -7 0 10 0 10 1 1 1 -10 10 -9 9
Sample Output 1
1 19
Hint
-100000000 <= a,b,c,x1,x2,y1,y2 <= 100000000
扩欧例题。
求范围中解的个数时用通解 列不等式:
x1 <= x0+k*b/gcd <= x2
y1 <= x0-k*a/gcd <= y2
变形可得到两个关于k的区间,求交集包含的整点个数即可
#include<bits/stdc++.h> #define lowbit(x) (x&(-x)) #define mst(a, b) memset(a, b, sizeof(a)) using namespace std; typedef long long LL; typedef unsigned long long ULL; LL read() { LL o=0, f=1; char ch; while(!isdigit(ch=getchar())) if(ch == '-') f=-1; while(isdigit(ch)) o=o*10+ch-'0', ch = getchar(); return o*f; } const int maxn = 100005, maxm = 500005; LL Exgcd(LL a, LL b, LL &x, LL &y) { if(b == 0) { x=1, y=0; return a; } LL gcd = Exgcd(b, a%b, y, x); y = y-a/b*x; return gcd; } int len(double a, double b, double c, double d) { // 求[a,b],[c,d]交集含整点个数 a = ceil(a), c = ceil(c), b = floor(b), d = floor(d); return max((int)((min(b, d)-max(a, c)))+1, 0); } LL a, b, c, d, x, y, X, Y; inline bool inRangex(LL n) { return x<=n && n<=X; } inline bool inRangey(LL n) { return y<=n && n<=Y; } int main() { LL n = read(); while(n--) { a=read(), b=read(), c=read(), x=read(), X=read(), y=read(), Y=read(); if(x>X || y>Y) { puts("0"); continue; } c = -c; // ax+by=c //a, b, c都要进行非负处理orz if(c<0) c=-c, a=-a, b=-b; if(a<0) a=-a, swap(x=-x, X=-X); if(b<0) b=-b, swap(y=-y, Y=-Y); if(!a && !b) { printf("%lld\n", c ? 0 : (LL)(X-x+1)*(Y-y+1)); } else if(!a) { if(c%b != 0 || !inRangey(c/b)) puts("0"); else printf("%d\n", X-x+1); } else if(!b) { if(c%a != 0 || !inRangex(c/a)) puts("0"); else printf("%d\n", Y-y+1); } else { LL x0, y0; LL gcd = Exgcd(a, b, x0, y0); if(c%gcd != 0) { puts("0"); continue; } a/=gcd, b/=gcd, c/=gcd; x0 *= c, y0 *= c; printf("%d\n", len(1.0*(x-x0)/b, 1.0*(X-x0)/b, 1.0*(y0-Y)/a, 1.0*(y0-y)/a)); } } return 0; }