表达整数的奇怪方式(EXCRT

# 题意

给定2n个整数,a1 , a2 , ...... , an 、m1 , m2 , ...... , mn,

求一个最小的正整数x,满足∀ 1≤i≤n , x ≡  mi (mod ai)

如果不存在解输出"-1",否则输出最小的正整数x

数据范围:

1 ≤ a≤ 231-1

1 ≤ mi < ai

1 ≤ n ≤ 25

# 题解

先考虑前两个式子:

x ≡  m1 (mod a1) ↔ x = k1 * a1 + m1

x ≡  m2 (mod a2) ↔ x = k2 * a2 + m2

k1 * a1 + m1  k2 * a2 + m2

k1 * a1 -k2 * a2 = m2-m1

判断一下有没有解即 gcd(a1,a2) |(m2-m1) 是否成立

扩展欧求出 k1 * a1 -k2 * a2 = gcd(a1,a2) 的解k1''k2''

k1'=k1'' * (m2-m1)/gcd(a1,a2

k2'=k2'' * (m2-m1)/gcd(a1,a2

由x = k1 * a1 + m1或x = k2 * a2 + m2都可以得到x的通解

其中k1通解=k+ k* (a2/gcd(a1,a2))显然k1取得最小值的时候x最小

但是在和后面的式子合并的时候有了新的约束,

x的最小值可能会改变所以先不具体求出x,

用得到的k1或k2的通解构成一个新的同余等式

k1通解=k1' + k* ( a2/gcd(a1,a2) )带入x = k1 * a1 + m1

x = ( k1' + k* ( a2/gcd(a1,a2) ) ) * a1 + m1

x = k * ( a* a2 )/gcd(a1,a2) + k1'*a1+m1

a'=( a* a)/gcd(a1,a2) , m'=k1'*a1+m1

x = k * a' + m'

x = k3 * a3 + m3

不断的合并到k-1,根据k的通解求得最小的x,

k = k0 + t * (an/gcd(a',an)) 

显然k0 % (an/gcd(a',an)) 即最小的解

 

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 ll n;
 5 ll exgcd(ll a,ll b,ll &x,ll &y){
 6     if(b==0){
 7         x=1;y=0;
 8         return a;
 9     }
10     ll d=exgcd(b,a%b,y,x);
11     y-=(a/b)*x;
12     return d;
13 }
14 int main(){
15     cin>>n;
16     ll a1,m1;
17     cin>>a1>>m1;
18     for(int i=0;i<n-1;i++){
19         ll a2,m2,k1,k2;
20         cin>>a2>>m2;
21         ll d=exgcd(a1,a2,k1,k2);//式子中的a2系数当作正数传入,得到的k可能为负数
22         if((m2-m1)%d) {puts("-1");return 0;}
23         k1*=(m2-m1)/d;//由裴蜀定理的解转化为方程解
24         ll t=(a2/d);
25         k1=(k1%t+t)%t;//对负数取模
26         m1=k1*a1+m1;
27         a1=a1/d*a2;
28     }
29     cout<<(m1%a1+a1)%a1<<endl;
30     return 0;
31 }

 

 

 

posted @ 2020-04-06 22:42  Hyx'  阅读(230)  评论(0编辑  收藏  举报