HDOJ1573 X问题[中国剩余定理]

X问题

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1792    Accepted Submission(s): 534


Problem Description
求在小于等于N的正整数中有多少个X满足:X mod a[0] = b[0], X mod a[1] = b[1], X mod a[2] = b[2], …, X mod a[i] = b[i], … (0 < a[i] <= 10)。
 

 

Input
输入数据的第一行为一个正整数T,表示有T组测试数据。每组测试数据的第一行为两个正整数N,M (0 < N <= 1000,000,000 , 0 < M <= 10),表示X小于等于N,数组a和b中各有M个元素。接下来两行,每行各有M个正整数,分别为a和b中的元素。
 

 

Output
对应每一组输入,在独立一行中输出一个正整数,表示满足条件的X的个数。
 

 

Sample Input
3 10 3 1 2 3 0 1 2 100 7 3 4 5 6 7 8 9 1 2 3 4 5 6 7 10000 10 1 2 3 4 5 6 7 8 9 10 0 1 2 3 4 5 6 7 8 9
 

 

Sample Output
1 0 3
 

 

Author
lwg
 

 

Source
 

 

Recommend
linle
 
 
 
 
 
 
 

 转自:http://hi.baidu.com/nicker2010/item/da4754d5f5097c8c6cce3fed

解题思路:
1.因为(a1,a2,a3,a4,….,ak)不一定互质,所以不能够直接用中国剩余定理。
2.x=r1+a1*k1,x=r2+a2*k2,所以有r1+a1*k1=r2+a2*k2,化简后得到 a1*k1=(r2-r1) mod(a2);
用扩展欧几里得可以得到最小的k1,所以x=r1+a1*k1+a1*a2/gcd(a1,a2),
就这样一直替换最后剩余一个同余方程。r1就是最后的解。

对于x=a1 mod b1,x= a2 mod b2,设x=a1+m*b1
所以b1*m=a2-a1 mod b2,利用欧几里德扩展定理求出最小的非负m,
那么x=a1+m*b1就已知,且x最小,如果无解,整个同余式组无解
同时,x+k*b1是所有满足x=a1 mod b1的解,而x+k'*b2又是所有满足x=a2 mod b2的解
那么,将x+k*b1与x+k'*b2合并,得到的式子就是x+k*lcm(b1,b2)
于是,上面两个式子可以用x'=x mod lcm(b1,b2)来替代
最后,就只剩下一个式子了,求得的最小的x就是答案
对于一次同余式ax=b mod n,设d=gcd(a,n),则同余式有解的充要条件为d|b
假设d=a*x'+n*y',则x0=b/d*x'一定为方程组的一个解,且共有d个解,
(证明可以参考算法导论)最小正整数解为(x0%n/d+n/d)%(n/d)

code:

 1 #include <iostream>
 2 #include <vector>
 3 using namespace std;
 4 long long exgcd(long long a,long long b,long long &x,long long &y)
 5 {
 6     if(a==0)
 7     {x=0;y=1;return b;}
 8     long long g = exgcd(b%a,a,x,y);
 9     long long tem = y;
10     y=x;
11     x=tem-(b/a)*y;
12     return g;
13 }
14 long long CRT(const vector<long long>& m,const vector<long long>& b,long long& lcm)
15 {
16     bool flag = false;
17     long long x, y, i,d,result,a1,m1,a2,m2,Size=m.size();
18     m1 = m[0]; a1 = b[0];
19     for(i=1;i<Size;++i)
20     {
21         m2 = m[i]; a2 = b[i];
22         d = exgcd( m1, m2, x, y );
23         if((a2-a1)%d != 0) flag = true;
24         result = (x * ((a2-a1) / d ) % m2 + m2 ) % m2;
25         a1 = a1 + m1 * result; //对于求多个方程
26         m1 = (m1 * m2) / d;    //lcm(m1,m2)最小公倍数
27         a1 = (a1 % m1 + m1) % m1;
28     }
29     lcm = m1;
30     if (flag) return -1;
31     else return a1;
32 }
33 int main()
34 {
35     long long T,N,M,i,num,ans,lcm,result;
36     vector<long long> miVec,biVev;
37     cin>>T;
38     while(T--)
39     {
40         cin>>N>>M;
41         miVec.clear();biVev.clear();
42         for(i=0;i<M;++i)
43         {cin>>num;miVec.push_back(num);}
44         for(i=0;i<M;++i)
45         {cin>>num;biVev.push_back(num);}
46         ans = CRT(miVec,biVev,lcm);
47         if(ans<0){cout<<0<<endl;continue;}
48         if(N<ans) result = 0;
49         else result=(N-ans)/lcm + 1;
50         if(ans==0)--result;
51         cout<<result<<endl;
52     }
53     return 0;
54 }

转自:http://yzmduncan.iteye.com/blog/1323599

数论——中国剩余定理(互质与非互质)

中国剩余定理

     中国剩余定理是中国古代求解一次同余方程组的方法,是数论中的一个重要定理。

     设m1,m2,m3,...,mk是两两互素的正整数,即gcd(mi,mj)=1,i!=j,i,j=1,2,3,...,k.

则同余方程组:

x = a1 (mod n1)

x = a2 (mod n2)

...

x = ak (mod nk)

模[n1,n2,...nk]有唯一解,即在[n1,n2,...,nk]的意义下,存在唯一的x,满足:

x = ai mod [n1,n2,...,nk], i=1,2,3,...,k。

解可以写为这种形式:

x = sigma(ai* mi*mi') mod(N)

      其中N=n1*n2*...*nk,mi=N/ni,mi'为mi在模ni乘法下的逆元。

中国剩余定理非互质版

    中国剩余定理求解同余方程要求模数两两互质,在非互质的时候其实也可以计算,这里采用的是合并方程的思想。下面是详细推导。


原文地址:https://www.cnblogs.com/XBWer/p/2632122.html