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 }
View Code

猜你喜欢

转载自www.cnblogs.com/Al-Ca/p/11227940.html
今日推荐