zoukankan      html  css  js  c++  java
  • 【模拟7.22】方程的解(拓展欧几里德)

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

    首先凭借数据性质和暴力,我们可以愉快的拿到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
    ");
     45              continue;
     46           }
     47           else if((aa<=0&&cc>=0)||(aa>=0&&cc<=0))
     48           {
     49                 printf("0
    ");
     50                 continue;
     51           }
     52           else printf("ZenMeZheMeDuo
    ");
     53           continue;
     54       }
     55       if(aa==0)
     56       {
     57           if(cc%bb!=0)
     58           {
     59             printf("0
    ");
     60             continue;
     61           }
     62           else if((bb<=0&&cc>=0)||(bb>=0&&cc<=0))
     63           {
     64                 printf("0
    ");
     65                 continue;
     66           }
     67           else printf("ZenMeZheMeDuo
    ");
     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
    ");
     77            continue;
     78       }
     79       if((aa<0&&bb>0)||(aa>0&&bb<0))
     80       {
     81           printf("ZenMeZheMeDuo
    ");
     82           continue;
     83       }
     84       exgcd(aa,bb,x1,y1);
     85       k=(double)(y2-y1)/(x2-x1);
     86       if(k>0)
     87       {
     88           printf("ZenMeZheMeDuo
    ");
     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
    ",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
    ",l,r);
    111       //printf("l1=%lld l2=%lld r1=%lld r2=%lld
    ",l1,l2,r1,r2);
    112       if(r-l<0)
    113       {
    114          printf("0
    ");
    115          continue;
    116       }
    117       else 
    118       {
    119           if(r-l+1>65535)
    120           {
    121              printf("ZenMeZheMeDuo
    ");
    122           }
    123           else
    124             printf("%lld
    ",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
    ");
     38         return 1;
     39     }
     40     else 
     41     {
     42         if((z-1)>65535)
     43         {
     44             printf("ZenMeZheMeDuo
    ");
     45             return 1;
     46         }
     47         else
     48         {
     49             printf("%lld
    ",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
    ");
     68               continue;
     69            }
     70       }
     71       if(aa>=0&&bb>=0)
     72       {
     73           if(cc<aa+bb)
     74           {
     75               printf("0
    ");
     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
    ");
     86          continue;
     87       }
     88       if(aa<bb)swap(bb,aa);
     89       if(aa*bb>0)
     90       {
     91          if(cc==0)
     92          {
     93              printf("0
    ");
     94              continue;
     95          }
     96       }
     97       if(aa==0&&bb==0&&cc==0)
     98       {
     99            printf("ZenMeZheMeDuo
    ");
    100            continue;
    101       }
    102       if(aa==0&&bb==0)
    103       {
    104          printf("0
    ");
    105          continue;
    106       }
    107       if(bb==0)
    108       { 
    109           if(cc%aa!=0)
    110           {
    111              printf("0
    ");
    112              continue;
    113           }
    114           else if((aa<=0&&cc>=0)||(aa>=0&&cc<=0))
    115           {
    116                 printf("0
    ");
    117                 continue;
    118           }
    119           else printf("ZenMeZheMeDuo
    ");
    120           continue;
    121       }
    122       if(aa==0)
    123       {
    124           if(cc%bb!=0)
    125           {
    126             printf("0
    ");
    127             continue;
    128           }
    129           else if((bb<=0&&cc>=0)||(bb>=0&&cc<=0))
    130           {
    131                 printf("0
    ");
    132                 continue;
    133           }
    134           else printf("ZenMeZheMeDuo
    ");
    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
    ");
    142            continue;
    143       }
    144       if((aa<0&&bb>0)||(aa>0&&bb<0))
    145       {
    146           printf("ZenMeZheMeDuo
    ");
    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
    ",ans);
    162       else
    163             printf("ZenMeZheMeDuo
    ");
    164    }
    165 }
    166 /*
    167 11
    168 -1733561 -7985280 -4117480 
    169 1553555 3269642 9835368 
    170 */
    View Code
  • 相关阅读:
    Eclipse 安装C++
    工厂模式
    程序员7年和我的7点感想――我的程序人生
    Java中的==和equals区别
    编程之美1
    Java_Ant详解
    我用电脑说爱你
    Oracle分页的SQL语句
    使用js获取父窗口iframe的高度
    Oracle PLSQL中 左连接和右连接用法
  • 原文地址:https://www.cnblogs.com/Wwb123/p/11228583.html
Copyright © 2011-2022 走看看