题意:http://www.lightoj.com/volume_showproblem.php?problem=1306
在范围内 求出满足ax+b*y+c=0的解 典型的扩展欧几里得
首先我们可以求出ax+by=gcd(a,b)=g的一个组解(x0,y0).而要使ax+by=c有解,必须有c%g==0.
继而可以得到ax+by=c的一个组解x1=c*x0/g , y1=c*y0/g
这样可以得到ax+by=c的通解为:
x=x1+b*t;//为了范围更大这里的 b=b/g; a=a/g
y=y1-a*t;
表达式为 x=x0*c/g+b*t/g
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> #include<map> #include<vector> #include<math.h> #include<string> using namespace std; #define INF 0x3f3f3f3f #define LL long long #define N 10006 #define Lson rood<<1 #define Rson rood<<1|1 LL exgcd(LL a,LL b,LL &x,LL &y)///扩展欧几里得 算出ax+by=gcd(a,b)的一组解 { if(b==0) { x=1;y=0; return a; } else { LL g=exgcd(b,a%b,x,y); LL t=x; x=y; y=t-a/b*y; return g; } } LL sign(LL a) { if(a==0) return 0; return a>0?1:-1; } LL ceil(LL a,LL b) { LL s=sign(a)*sign(b); return b/a+(b%a!=0&&s>0); } LL floor(LL a,LL b) { LL s=sign(a)*sign(b); return b/a-(b%a!=0&&s<0); } int main() { int T,t=1; scanf("%d",&T); while(T--) { LL a,b,c,x1,x2,y1,y2; scanf("%lld %lld %lld %lld %lld %lld %lld,",&a,&b,&c,&x1,&x2,&y1,&y2); printf("Case %d: ",t++); if(!a&&!b)///三个特判 a与b为0 的处理 { if(c) printf("0 "); else printf("%lld ",(x2-x1+1)*(y2-y1+1)); continue; } else if(!a) { if(c%b) printf("0 "); else if((-c/b)>=y1&&(-c/b)<=y2) printf("%lld ",x2-x1+1); else printf("0 "); continue; } else if(!b) { if(c%a) printf("0 "); else if((-c/a)>=x1&&(-c/a)<=x2) printf("%lld ",y2-y1+1); else printf("0 "); continue; } LL x,y; LL g=exgcd(a,b,x,y); if(c%g!=0){///求出一组解 判断是否有解 printf("0 "); continue; }///因为是一元一次方程 需要看清是递增还是递减 然后在处理 if(sign(g)*sign(b)<0) swap(x1,x2); LL k1=ceil(b,g*x1+c*x);//因为是小值 有部分已经占用 需要向上取整 LL k2=floor(b,g*x2+c*x);//同理 向下取整 if(sign(-a)*sign(g)<0) swap(y1,y2); LL k3=ceil(-a,g*y1+c*y); LL k4=floor(-a,g*y2+c*y); k1=max(k1,k3); k2=min(k2,k4); if(k1>k2) printf("0 "); else printf("%lld ",k2-k1+1); } return 0; }