HZOJ 方程的解
乍一看还以为是道水题,没想到这玩意这么难搞。
看题显然是exgcd,然而exgcd求的是一个解而不是解的个数(考试的时候不记得通解的式子然后挂了)。
对于40%的数据,直接枚举计数即可。
对于另为20%,a+b=c,puts("1");
这60分差不多是送的。
剩下的就是比较恶心的了:
先讨论都是正数的情况:$ax+by=c$,exgcd可以求$ax+by=gcd(a,b)$的解x0,y0,设t=c/gcd(a,b);则$a*tx_0+b*ty_0=t*gcd(a,b)=c$.
那么我们就求出了方程的一组特解,方程的通解为$x=x_0+kb,y=y_0-ka$,那么可以枚举k计数(加一些优化可以拿到这20分),但这样太慢。
能不能不用枚举呢?a/=gcd(a,b),b/=gca(a,b),c/=gcd(a,b)=t;因为$x=x_0+kb$,将x0模b(如果<=0,+b),得到x0的最小正数解(此时k最小),$ax+by=c$得$y_0=(c-a*x_0)/b$,
那么我们就的到了y0的最大解,y0%=a,那么我们得到了y0的最小正数解,则ans=(y0-miny)/a0+1。
那么对于负数呢?
只需要将a,b变为正数求解,之后将a,b与求得的x0,y0同乘-1,等式仍然成立。
1 #include<iostream> 2 #include<cstdio> 3 #define LL long long 4 #define int LL 5 using namespace std; 6 int T,a,b,c; 7 int gcd(int a,int b){return b==0?a:gcd(b,a%b);} 8 int exgcd(int a,int b,int &x,int &y) 9 { 10 if(!b){x=1,y=0;return a;} 11 int gcd=exgcd(b,a%b,x,y),t=x; 12 x=y,y=t-a/b*y; 13 return gcd; 14 } 15 inline int read(); 16 signed main() 17 { 18 // freopen("in.txt", "r", stdin); 19 // freopen("0.out", "w", stdout); 20 cin>>T; 21 while(T--) 22 { 23 cin>>a>>b>>c; 24 if(a==0&&b==0&&c==0){puts("ZenMeZheMeDuo");continue;} 25 if(a==0&&b==0&&c!=0){puts("0");continue;} 26 if(a==0&&c==0){puts("ZenMeZheMeDuo");continue;} 27 if(a==0&&c%b==0&&c/b>0){puts("ZenMeZheMeDuo");continue;} 28 if(a==0){puts("0");continue;} 29 if(b==0&&c==0){puts("ZenMeZheMeDuo");continue;} 30 if(b==0&&c%a==0&&c/a>0){puts("ZenMeZheMeDuo");continue;} 31 if(b==0){puts("0");continue;} 32 if(a<0&&b<0&&c<0){a=-a,b=-b,c=-c;} 33 if(a==1&&b==1)// 34 { 35 if(c>=65536){puts("ZenMeZheMeDuo");continue;} 36 else {printf("%lld\n",c-1);continue;} 37 } 38 if(a+b==c){puts("1");continue;} 39 if(a<=1000&&b<=1000&&c<=1000&&a>0&&b>0&&c>0)// 40 { 41 int ans=0; 42 for(int x=1;x<=c;x++) 43 { 44 for(int y=1;y<=c;y++) 45 { 46 if(a*x+b*y==c)ans++; 47 if(ans>=65536)break; 48 } 49 if(ans>=65536)break; 50 } 51 if(ans>=65536){puts("ZenMeZheMeDuo");continue;} 52 else {printf("%lld\n",ans);continue;} 53 } 54 else 55 { 56 int fa=0,fb=0; 57 if(c<0)a=-a,b=-b,c=-c; 58 if(a<0)a=-a,fa=1; 59 if(b<0)b=-b,fb=1; 60 int GCD=gcd(a,b); 61 if(c%GCD!=0){puts("0");continue;} 62 int t=c/GCD,x0,y0; 63 exgcd(a,b,x0,y0);x0*=t;y0*=t; 64 int a0=a/GCD,b0=b/GCD;c=t; 65 if(fa)a0=-a0,x0=-x0; 66 if(fb)b0=-b0,y0=-y0; 67 if(a0<0)a0=-a0,b0=-b0,c=-c; 68 if(a0*b0<0){puts("ZenMeZheMeDuo");continue;} 69 x0=x0%b0; 70 if(x0<=0)x0+=b0; 71 y0=(c-a0*x0)/b0; 72 if(y0<0){puts("0");continue;} 73 LL miny=y0%a0; 74 if(miny==0)miny+=a0;// 75 if(miny>y0){puts("0");continue;} 76 else 77 { 78 int ans=(y0-miny)/a0+1; 79 if(ans>=65536){puts("ZenMeZheMeDuo");continue;} 80 else {printf("%lld\n",ans);continue;} 81 } 82 } 83 } 84 } 85 inline int read() 86 { 87 int s=0,f=1;char a=getchar(); 88 while(a<'0'||a>'9'){if(a=='-')f=-1;a=getchar();} 89 while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();} 90 return s*f; 91 }
波澜前,面不惊。