方程的解(拓展欧几里德)

本来以为这题会挂结果就这题水了点分.....

首先凭借数据性质和暴力,我们可以愉快的拿到60分。

至于正解QAQ

那么就要联系起一个简单却不常用的知识。

*******************************************

拓展欧几里德:

首先ax+by=gcd(x,y);这是显然的道理,

然后该式等价于bx+(a%b)y=gcd(a,b);

我们想想发现该式子若是最后a%b==0,则x=1,y=0返回。

在回溯时我们需要将该层的x,y求出。

那么我们设回溯过来的x为x' y为y'。

bx'+(a%b)y'=gcd(a,b)可整理为ay'+b(x'-a/b*y')=gcd(a,b);

这样是不是和一开始的式子很像

我们为了求出x和y,于是先设个数z防止x的值被修改

z=x,x=y;y=z-a/b*y;

代码:

 1 void exgcd(ll a,ll b,ll &x,ll &y)
 2 {
 3    if(b==0)
 4    {
 5         x=1;y=0;return ;
 6    }
 7    exgcd(b,a%b,x,y);
 8    ll z=x;x=y;y=z-(a/b)*y;
 9    return ;
10 }
View Code

******************************************

正解:

1.(这是我自己推的,有点麻烦,建议看下一个)

首先我们能得到一个通解,x=c/d*x0+k*b/d;(x0为exgcd解,d为gcd解)这里k是个变量,可以加可以减。

所以相应的y也可以取值,我们已知x>0&&y>0所以我们可以借此来求出不等关系

注意不等关系本来是四个方程,但因为x0,y0的大小关系,所以会缩为两个。

此时求出k的取值范围,即求出x,y的取值范围,kmax-kmin即为结果。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<string>
  5 #include<algorithm>
  6 #include<cmath>
  7 #include<stack>
  8 #include<vector>
  9 #include<queue>
 10 #include<bits/stdc++.h>
 11 #define MAXN 401
 12 #define ps push_back
 13 #define ll long long
 14 using namespace std;
 15 ll aa,bb,cc;
 16 ll T;
 17 void exgcd(ll a,ll b,ll &x,ll &y)
 18 {
 19    if(b==0)
 20    {
 21         x=1;y=0;return ;
 22    }
 23    exgcd(b,a%b,x,y);
 24    ll z=x;x=y;y=z-(a/b)*y;
 25    return ;
 26 }
 27 ll gcd(ll a,ll b)
 28 {
 29   return (b!=0)?gcd(b,a%b):a;
 30 }
 31 int main()
 32 {
 33    //freopen("text.in","r",stdin);
 34    //freopen("wa.out","w",stdout);
 35    scanf("%lld",&T);
 36    while(T--)
 37    {
 38       scanf("%lld%lld%lld",&aa,&bb,&cc);
 39       if(aa<=0&&bb<=0){aa=-aa;bb=-bb;cc=-cc;}
 40       if(bb==0)
 41       { 
 42           if(cc%aa!=0)
 43           {
 44              printf("0\n");
 45              continue;
 46           }
 47           else if((aa<=0&&cc>=0)||(aa>=0&&cc<=0))
 48           {
 49                 printf("0\n");
 50                 continue;
 51           }
 52           else printf("ZenMeZheMeDuo\n");
 53           continue;
 54       }
 55       if(aa==0)
 56       {
 57           if(cc%bb!=0)
 58           {
 59             printf("0\n");
 60             continue;
 61           }
 62           else if((bb<=0&&cc>=0)||(bb>=0&&cc<=0))
 63           {
 64                 printf("0\n");
 65                 continue;
 66           }
 67           else printf("ZenMeZheMeDuo\n");
 68           continue;
 69       }
 70       ll x1=0,y1=0,x2=0,y2=0;
 71       double k=0,h=0;
 72       ll gcdd=gcd(abs(aa),abs(bb));
 73       ll gg=cc/gcdd;
 74       if(abs(cc)%abs(gcdd)!=0)
 75       {
 76            printf("0\n");
 77            continue;
 78       }
 79       if((aa<0&&bb>0)||(aa>0&&bb<0))
 80       {
 81           printf("ZenMeZheMeDuo\n");
 82           continue;
 83       }
 84       exgcd(aa,bb,x1,y1);
 85       k=(double)(y2-y1)/(x2-x1);
 86       if(k>0)
 87       {
 88           printf("ZenMeZheMeDuo\n");
 89           continue; 
 90       }
 91       ll r1=100000000,r2=100000000,l1=0,l2=0;
 92       ll kx1=(cc/gcdd)*x1;ll kx2=(cc/gcdd)*y1;
 93       ll base1=(bb/gcdd);ll base2=(aa/gcdd);
 94       //printf("kx1+%lld k2=%lld base1=%lld base2=%lld\n",kx1,kx2,base1,base2);
 95       if(x1>0)
 96       {
 97           if(kx1%base1==0)
 98           r1=kx1/base1-1;
 99           else r1=kx1/base1;
100       }
101       if(y1>0)
102       {
103           if(kx2%base2==0)
104           r2=kx2/base2-1;
105           else r2=kx2/base2;
106       }
107       if(x1<=0)l1=(-kx1)/base1+1;
108       if(y1<=0)l2=(-kx2)/base2+1;
109       ll l=max(l1,l2);ll r=min(r1,r2);
110       //printf("l=%lld r=%lld\n",l,r);
111       //printf("l1=%lld l2=%lld r1=%lld r2=%lld\n",l1,l2,r1,r2);
112       if(r-l<0)
113       {
114          printf("0\n");
115          continue;
116       }
117       else 
118       {
119           if(r-l+1>65535)
120           {
121              printf("ZenMeZheMeDuo\n");
122           }
123           else
124             printf("%lld\n",r-l+1);
125       }
126    }
127 }
View Code

2.(参考zzn的做法,其实本质上差不多)

x=c/d*x0+k*b/d;不变的方程

我们先给x0,y0同时乘上c/d;这样就是所求ax+by=c中的x和y

我们易发现x每次增加b,y每次减少等量a结果不变,那么我们就能愉快的A掉

现将x%b(为防止x过大)得出当x>=1时y=(c-ax)/b得出ymax;

然后将y%a,得出了y>=1时y的min

(如果y<0||x<0先相应++a,++b)

这样我们得到了y的取值范围又知y每次增加a*k

所以令(ymax-ymin)/a即为结果

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<string>
  5 #include<algorithm>
  6 #include<cmath>
  7 #include<stack>
  8 #include<vector>
  9 #include<queue>
 10 #include<bits/stdc++.h>
 11 #define MAXN 401
 12 #define ps push_back
 13 #define ll long long
 14 using namespace std;
 15 ll aa,bb,cc;
 16 ll T;
 17 void exgcd(ll a,ll b,ll &x,ll &y)
 18 {
 19    if(b==0)
 20    {
 21         x=1;y=0;return ;
 22    }
 23    exgcd(b,a%b,x,y);
 24    ll z=x;x=y;y=z-(a/b)*y;
 25    return ;
 26 }
 27 ll gcd(ll a,ll b)
 28 {
 29   return (b!=0)?gcd(b,a%b):a;
 30 }
 31 ll work1(ll x,ll y,ll z)
 32 {
 33     if(x!=y)return 0;
 34     if(x!=1)return 0;
 35     if(z<=0)
 36     {
 37         printf("0\n");
 38         return 1;
 39     }
 40     else 
 41     {
 42         if((z-1)>65535)
 43         {
 44             printf("ZenMeZheMeDuo\n");
 45             return 1;
 46         }
 47         else
 48         {
 49             printf("%lld\n",z-1);
 50             return 1;
 51         }
 52     }
 53 }
 54 int main()
 55 {
 56    //freopen("text.in","r",stdin);
 57    //freopen("wa.out","w",stdout);
 58    scanf("%lld",&T);
 59    while(T--)
 60    {
 61       scanf("%lld%lld%lld",&aa,&bb,&cc);
 62       if(aa<0&&bb<0)
 63       {
 64            aa-=2*aa;bb-=2*bb;cc-=2*cc;
 65            if(cc<aa+bb)
 66            {
 67               printf("0\n");
 68               continue;
 69            }
 70       }
 71       if(aa>=0&&bb>=0)
 72       {
 73           if(cc<aa+bb)
 74           {
 75               printf("0\n");
 76               continue;
 77           }
 78       }
 79       if(work1(aa,bb,cc)==1)
 80       {
 81            continue;
 82       }
 83       if(aa+bb==cc&&aa>0&&bb>0)
 84       {
 85          printf("1\n");
 86          continue;
 87       }
 88       if(aa<bb)swap(bb,aa);
 89       if(aa*bb>0)
 90       {
 91          if(cc==0)
 92          {
 93              printf("0\n");
 94              continue;
 95          }
 96       }
 97       if(aa==0&&bb==0&&cc==0)
 98       {
 99            printf("ZenMeZheMeDuo\n");
100            continue;
101       }
102       if(aa==0&&bb==0)
103       {
104          printf("0\n");
105          continue;
106       }
107       if(bb==0)
108       { 
109           if(cc%aa!=0)
110           {
111              printf("0\n");
112              continue;
113           }
114           else if((aa<=0&&cc>=0)||(aa>=0&&cc<=0))
115           {
116                 printf("0\n");
117                 continue;
118           }
119           else printf("ZenMeZheMeDuo\n");
120           continue;
121       }
122       if(aa==0)
123       {
124           if(cc%bb!=0)
125           {
126             printf("0\n");
127             continue;
128           }
129           else if((bb<=0&&cc>=0)||(bb>=0&&cc<=0))
130           {
131                 printf("0\n");
132                 continue;
133           }
134           else printf("ZenMeZheMeDuo\n");
135           continue;
136       }
137       ll gcdd=gcd(abs(aa),abs(bb));
138       ll gg=cc/gcdd;
139       if(abs(cc)%abs(gcdd)!=0)
140       {
141            printf("0\n");
142            continue;
143       }
144       if((aa<0&&bb>0)||(aa>0&&bb<0))
145       {
146           printf("ZenMeZheMeDuo\n");
147           continue;
148       }
149       ll x1=0,y1=0;
150       exgcd(aa,bb,x1,y1);
151       ll ans=0;
152       x1*=cc/gcdd;y1*=cc/gcdd;
153       aa/=gcdd,bb/=gcdd,cc/=gcdd;x1%=bb;
154       while(x1<=0) x1+=bb;
155       y1=(cc-aa*x1)/bb;
156       ll y2=y1%aa;
157       while(y2<=0) y2+=aa;
158       ans=(y1-y2)/aa+1;
159       if(y2>y1) ans=0;
160       if(ans<=65535)
161             printf("%lld\n",ans);
162       else
163             printf("ZenMeZheMeDuo\n");
164    }
165 }
166 /*
167 11
168 -1733561 -7985280 -4117480 
169 1553555 3269642 9835368 
170 */
View Code

猜你喜欢

转载自www.cnblogs.com/Wwb123/p/11228583.html