题意:求解方程ax+by+c=0,在区间x1->x2和y1->y2的解的个数。
看似简单,真心a的不容易啊!开始跪于第8组数据,原因是没用long long !后来改了,跪于12组,超时,于是,换方法,求出x的解,对应到y
,然后算在y1,y2的解有几个(不要用枚举法,算有几个就行)。竟然又跪于第4组数据!!哎,弱爆了。
才发现,x对应过去的y,x递增,y未必也递增,也未必递减啊!!
做线方程总结:
先判断有无解,再约分后得 ax+by=c,用扩展欧几里得求得ax+by=1的一解,x=x*c,y=y*c,便是原方程一组解了,
每俩个相邻解x,相差|b|,同理,y差|a|,然后就是看题目要求了,见招拆招了,如想要到去某点附近的解,
可以 x=x-(x1-x)/abs(b)*abs(b);(可能左右)。
#include<iostream> #include<cmath> using namespace std; long long gcd(long long a,long long b) { return b==0?a:gcd(b,a%b); } void exgcd(long long a,long long b,long long &x,long long &y) { if(b==0){x=1;y=0;} else { exgcd(b,a%b,y,x);y=y-x*(a/b); } } inline long long getabs(long long a) { return a<0?-a:a; } int main() { long long a,b,c,x1,x2,y1,y2; cin>>a>>b>>c>>x1>>x2>>y1>>y2; long long x,y; c=-c; //移项 if(x1>x2||y1>y2){cout<<0<<endl;return 0;} //排除无解的情况 if(a==0&&b==0) //特殊情况讨论 { long long ans=0; if(c==0) { ans=(x2-x1+1)*(y2-y1+1); //此处任意组合都可以 } cout<<ans<<endl; return 0; } if(a==0) { if(c%b!=0){cout<<0<<endl;return 0;} else { y=c/b; if(y>=y1&&y<=y2) cout<<x2-x1+1<<endl; else cout<<0<<endl; return 0; } } if(b==0) { if(c%a!=0){cout<<0<<endl;return 0;} else { x=c/a; if(x>=x1&&x<=x2)cout<<y2-y1+1<<endl; else cout<<0<<endl; return 0; } } long long g=getabs(gcd(a,b)); if(c%g!=0){cout<<0<<endl;return 0;} a=a/g;b=b/g;c=c/g; //约去最大公约数 exgcd(a,b,x,y); //求得一组解 x=x*c; y=y*c; //原方程一组解 x=x-(x-x1)/getabs(b)*getabs(b); //得与x1最近的一解x(x>=x1) while(x<x1)x+=getabs(b); if(x>x2){cout<<0<<endl;return 0;} long long xx=x+(x2-x)/getabs(b)*getabs(b); //解x->xx(x>=x1,xx<=x2) y=(c-a*x)/b; //对应yy,y,注意,此处yy,y大小不知道!! long long yy=(c-a*xx)/b; long long ans=0; /* while(x<=xx) //若用枚举解,超时 { if(y>=y1&&y<=y2)ans++; x+=getabs(b); y=(c-a*x)/b; }*/ if(yy>y){long long temp=y;y=yy;yy=temp;} //大小决定一下 if(yy<y1) //取在区间y1->y2之间的解。(y,yy为边界解) { yy=yy+(y1-yy)/getabs(a)*getabs(a); while(yy<y1)yy+=getabs(a); } if(y2<y) { y=y-(y-y2)/getabs(a)*getabs(a); while(y>y2)y-=getabs(a); } if(y>=yy) ans=(y-yy)/getabs(a)+1; cout<<ans<<endl; }