本来以为这题会挂结果就这题水了点分.....
首先凭借数据性质和暴力,我们可以愉快的拿到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 }
******************************************
正解:
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 }
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 */