[POJ 2891] Strange Way to Express Integers
Description
给定 k 个同余方程组,求出满足条件的最小正整数 x,或者无解输出 -1。
Solution
注意到模数不一定互质,所以中国剩余定理不能用
嗯有请扩展中国剩余定理
定理证明就不说了右转置顶博文
讲一下这道题怎么搞
假设我们已经把若干个式子合并为一个了,模数为 A,余数为 R。
那么对于新式子$k_1 \times A + R = k_2 \times a_i + r_i$
可以通过移项搞出来 $k_1 \times A + k_2 \times a_i = r_i - R$
发现了什么? 扩欧直接套上去啊!
等等,如果要判断有没有解怎么办?
中国剩余定理告诉我们此方程有解当且仅当 $gcd(A,a_i) \mid (r_i-R)$
那么我们就可以通过这一步判断是否应该输出 -1
然后我们扩欧瞎搞搞出来当前方程的解了:$k_1' \times A + k_2' \times a_i = gcd(A,a_i)$
之后呢?注意到求出来的 $k_1'$ 不是原方程的解,原方程的解应该是 $k_1 = k_1' \times \frac{r_i - R}{gcd(A,a_i)}$。
这一步很重要,因为 $k_1$ 有可能不是正数,所以要 $k_1 \%=\frac{a_i}{gcd(A,a_i)}$,这样才保证了 $k_1$ 是个正数。
然后就把 $k_1$ 代进关于 $x$ 的表达式即可求出 $x$ 的值。
还没完。当前求出来的 $x$ 只是这两个方程的特解,不是整个方程的通解。
我们设 $ans$ 为最后的答案。
易证 $ans \equiv x \quad(mod\;lcm(A,a_i))$
咦?这不是一个新的同余方程了么?
那我们是将两个同余方程合并成一个了啊。
就这样消下去最后只剩下一个同余方程就是最后答案了啊。
没错就是这样=.=
Code
1 #include<cstdio> 2 #include<cctype> 3 #define N 100005 4 #define int long long 5 6 signed k; 7 int a[N],r[N]; 8 9 int exgcd(int a,int b,int &x,int &y){ 10 if(!b){ 11 x=1,y=0; 12 return a; 13 } 14 int c=exgcd(b,a%b,x,y); 15 int t=x; 16 x=y; 17 y=t-a/b*y; 18 return c; 19 } 20 21 int CRT(){ 22 int A=a[1],R=r[1]; 23 int x,y; 24 for(int i=2;i<=k;i++){ 25 int d=exgcd(A,a[i],x,y); 26 if((r[i]-R)%d) return -1; 27 x*=(r[i]-R)/d; 28 int zj=a[i]/d; 29 ((x%=zj)+=zj)%=zj; 30 //x%=a[i]/d; 31 R+=x*A; 32 //A=A/d*a[i]; 33 A=A*a[i]/d; 34 } 35 int X=R; 36 X%=A; 37 X+=A; 38 X%=A; 39 return X; 40 } 41 42 signed main(){ 43 while(~(scanf("%d",&k))){ 44 for(int i=1;i<=k;i++) scanf("%lld%lld",&a[i],&r[i]); 45 printf("%lld\n",CRT()); 46 } 47 return 0; 48 }