方程的解 扩展欧几里德
题面加密
首先看到这道题就能想到用exgcd,但是怎么用,我们知道这种方程一有就是一堆解,那么这个题的限制就是解的个数,我们考虑如果把方程移项化简就能得到$y=\frac{c}{b}-\frac{a}{b}*x$,这时候就用到义务教育的知识了,当a,b异号那么一定同增,如果exgcd有解,一定是无限组,直接判掉。我们考虑ab同号,那么我们可以得到一定是过第一象限的递减直线,我们对方程做如下操作$a(x-b)+b(y+a)=c$,显然也是成立的,此时ab都可以化成正号,那么x减小则y增加,我们可以将x对b取模得到y的最大解,再将y对a取模得到y最小解,然后y的变换一定是一个等差数列,公差为a,则y的范围可以求,命题得解(装X)。
然后特判一下就A了,快读记得打负号
#include<iostream> #include<cstdio> #define ll long long using namespace std; ll rd() { ll s=0,w=1; char cc=getchar(); while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();} while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar(); return s*w; } ll exgcd(ll a,ll b,ll &x,ll &y,ll c) { if(b==0){x=c/a;y=0;return a;} ll d=exgcd(b,a%b,y,x,c); y-=a/b*x; return d; } int main() { // freopen("data.in","r",stdin); //freopen("data.ans","w",stdout); ll T=rd(),a,b,c,x,y,g,ans; while(T--) { a=rd(),b=rd(),c=rd(); //cout<<a<<" "<<b<<endl; if(!a&&!b) { if(!c)printf("ZenMeZheMeDuo\n"); else printf("0\n"); continue; } if(a<0&&b<0) a=-a,b=-b,c=-c; g=exgcd(a,b,x,y,c); if(c%g){puts("0");continue;} if(a==0) { if((b<=0&&c>=0)||(b>=0&&c<=0))printf("0\n"); else printf("ZenMeZheMeDuo\n"); continue; } if(b==0) { if((a<=0&&c>=0)||(a>=0&&c<=0))printf("0\n"); else printf("ZenMeZheMeDuo\n"); continue; } if(a*b<0) { printf("ZenMeZheMeDuo\n"); continue; } if(a<0&&b<0)a=-a,b=-b,c=-c; a/=g;b/=g;c/=g;x%=b; while(x<=0)x+=b; y=(c-a*x)/b; ll ymin=y%a;while(ymin<=0)ymin+=a; if(ymin>y)ans=0; else ans=(y-ymin)/a+1; if(ans>65535)printf("ZenMeZheMeDuo\n"); else printf("%lld\n",ans); } } /* g++ 6.cpp -o 6 ./6 4 1 -1 3 1 1 65536 1 1 65537 2 3 24 */
Zeit und Raum trennen dich und mich.时空将你我分开。