[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 }

猜你喜欢

转载自www.cnblogs.com/YoungNeal/p/8948023.html