首页 > 其他 > 详细

wenbao与中国剩余定理(孙子定理)

时间:2018-04-14 14:55:05      阅读:192      评论:0      收藏:0      [点我收藏+]

 

用来求解一般模线性方程,,

 

X %M1 == A1;

X %M2 == A2;

X %M3 == A3;

。。。。。

当M1, M2, M3,。。。互质时(关于不互质下面会提到),可以利用中国剩余定理求解。。

 

 

技术分享图片

 

技术分享图片

 

 

其中技术分享图片,而技术分享图片技术分享图片技术分享图片的逆元。

 

 

http://acm.hdu.edu.cn/showproblem.php?pid=1370

 

 1 #include <stdio.h>
 2 using namespace std;
 3 int n, s[4], x, y, d, w, b[] = {23, 28, 33};
 4 void exgcd(int a, int b, int& d, int& x, int& y){
 5     if(!b) d = a, x = 1, y = 0;
 6     else exgcd(b, a%b, d, y, x), y -= x*(a/b);
 7 }
 8 int solve(int *s){
 9     int M = 1, sum = 0, Mi;
10     for(int i = 0; i < 3; i++){
11         s[i]%=b[i];
12         M*=b[i];
13     }
14     for(int i = 0; i < 3; i++){
15         Mi = M/b[i];
16         exgcd(Mi, b[i], d, x, y);
17         sum = (sum + Mi*x*s[i]) % M;
18     }
19     sum = (M+sum%M)%M - w;
20     if(sum <= 0) sum += 21252;
21     return sum;
22 }
23 int main(){
24     scanf("%d", &n);
25     while(n--){
26         int num = 1;
27         while(scanf("%d %d %d %d", &s[0], &s[1], &s[2], &w)){
28             if(s[0] == -1 && s[1] == -1 && s[2] == -1) break;
29             printf("Case %d: the next triple peak occurs in %d days.\n", num++, solve(s));
30         }
31     }
32     return 0;
33 }

 

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

http://acm.fzu.edu.cn/problem.php?pid=1402

 

裸的剩余定理,,,,神奇的是fzu上面用VC可以过,但是用GNUC++却不可以,。。。。。。XXX

 

 1 #include <iostream>
 2 #include <stdio.h>
 3 using namespace std;
 4 #define ll long long
 5 ll a[20], b[20], sum;
 6 int t;
 7 void ex(ll a, ll b, ll& x, ll& y){
 8     if(!b) x = 1, y = 0;
 9     else ex(b, a%b, y, x), y -= x*(a/b);
10 }
11 ll Ch(){
12     ll xx = 0;
13     for(int i = 0; i < t; ++i){
14         ll sum2 = sum/a[i], x, y;
15         ex(sum2, a[i], x, y);
16         x = (x%a[i] + a[i])%a[i];
17         xx = (xx + sum2*x*b[i]%sum)%sum;
18     }
19     return xx;
20 }
21 int main(){
22     while(~scanf("%d", &t)){
23         sum = 1;
24         for(int i = 0; i < t; ++i){
25             scanf("%lld%lld", &a[i], &b[i]);
26             sum *= a[i];
27         }
28         printf("%lld\n", Ch());
29     }
30     return 0;
31 }

 

 

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

http://poj.org/problem?id=1006

 

裸的剩余定理。。。。

 

 1 #include <iostream>
 2 using namespace std;
 3 int p, e, i, d, sum = 21252, cnt = 0;
 4 int a[3] = {924, 759, 644};
 5 int b[3] = {23, 28, 33};
 6 int c[3];
 7 void xg(int a, int b, int &x, int &y){
 8     if(!b) x = 1, y = 0;
 9     else xg(b, a%b, y, x), y -= x*(a/b);
10 }
11 void Ch(){
12     //cout<<23*28*33<<" "<<23*28<<" "<<23*33<<" "<<28*33<<endl;
13     int num = 0, x, y;
14     for(int i = 0; i < 3; ++i){
15         xg(a[i], b[i], x, y);
16         x = (x%b[i] + b[i])%b[i];
17         num = (num + x*a[i]*c[i]%sum)%sum;
18     }
19     int xx = num - d;
20     if(xx <= 0) xx += sum;
21     printf("Case %d: the next triple peak occurs in %d days.\n", ++cnt, xx);
22     //printf("%d\n", xx);
23 }
24 int main(){
25     while(scanf("%d%d%d%d", &p, &e, &i, &d)){
26         if(p == -1 && e == -1 && i == -1 && d == -1) break;
27         c[0] = p % 23, c[1] = e % 28, c[2] = i % 33;
28         Ch();
29     }
30     return 0;
31 }

 

 

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

http://acm.hdu.edu.cn/showproblem.php?pid=5768

 

求X, Y之间减去(除pi余ai)后被7整除的数

剩余定理加容斥,。。。。涉及到枚举子集。。。

 

AC不易啊!!!!!

 

 1 #include <iostream>
 2 using namespace std;
 3 #define ll long long
 4 const int maxn = 20;
 5 int n;
 6 ll xxx, yyy, a[maxn], p[maxn];
 7 int b[maxn];
 8 void xg(ll a, ll b, ll &x, ll &y){
 9     if(!b) x = 1, y = 0;
10     else xg(b, a%b, y, x), y -= x*(a/b);
11 }
12 ll Ch(int xx){
13     int w;
14     ll sum = 7LL, x, y, sum2, num = 0;
15     for(int i = 0; i < xx; ++i){
16         w = b[i];
17         sum *= p[w];
18     }
19     for(int i = 0; i < xx; ++i){
20         w = b[i];
21         sum2 = sum/p[w];
22         xg(sum2, p[w], x, y);
23         x = (x%p[w]+p[w])%p[w];
24         num = (num + x*sum2%sum*a[w]%sum)%sum;
25     }
26     return (yyy-num+sum)/sum - (xxx-num+sum)/sum;
27 }
28 ll solve(){
29     ll sum = yyy/7 - xxx/7;
30     ll len = 1LL << n;
31     for(int i = 1; i < len; ++i){
32         int num = 0;
33         for(int j = 0; j < n; ++j){
34             if(i&(1<<j)) b[num++] = j;
35         }
36         if(num&1) sum -= Ch(num);
37         else sum += Ch(num);
38     }
39     return sum;
40 }
41 int main(){
42     int t;
43     scanf("%d", &t);
44     for(int j = 1; j <= t; ++j){
45         scanf("%d%lld%lld", &n, &xxx, &yyy);
46         xxx--;
47         for(int i = 0; i < n; ++i){
48             scanf("%lld%lld", p+i, a+i);
49         }
50         printf("Case #%d: %lld\n", j, solve());
51     }
52     return 0;
53 }

 

 


----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

当M1, M2, M3.。。不互质时,该怎么求解呢?

通过合并方程可以求解,,

 

转载:

/**********************一般模线性方程组***********************/

同样是求这个东西。。
X mod m1=r1
X mod m2=r2
...
...
...
X mod mn=rn

首先,我们看两个式子的情况
X mod m1=r1……………………………………………………………(1)
X mod m2=r2……………………………………………………………(2)
则有 
X=m1*k1+r1………………………………………………………………(*)
X=m2*k2+r2
那么 m1*k1+r1=m2*k2+r2
整理,得
m1*k1-m2*k2=r2-r1
令(a,b,x,y,m)=(m1,m2,k1,k2,r2-r1),原式变成
ax+by=m
熟悉吧?

此时,因为GCD(a,b)=1不一定成立,GCD(a,b) | m 也就不一定成立。所以应该先判 若 GCD(a,b) | m 不成立,则!!!方程无解!!!。
否则,继续往下。

解出(x,y),将k1=x反代回(*),得到X。
于是X就是这两个方程的一个特解,通解就是 X‘=X+k*LCM(m1,m2)
这个式子再一变形,得 X‘ mod LCM(m1,m2)=X
这个方程一出来,说明我们实现了(1)(2)两个方程的合并。
令 M=LCM(m1,m2),R=r2-r1
就可将合并后的方程记为 X mod M = R。

然后,扩展到n个方程。
用合并后的方程再来和其他的方程按这样的方式进行合并,最后就能只剩下一个方程 X mod M=R,其中 M=LCM(m1,m2,...,mn)。
那么,X便是原模线性方程组的一个特解,通解为 X‘=X+k*M。

如果,要得到X的最小正整数解,就还是原来那个方法:

X%=M;
if (X<0) X+=M;

 

 

例题

http://poj.org/problem?id=2891

 

 

 1 #include <iostream>
 2 using namespace std;
 3 #define ll long long
 4 const int maxn = 1e5+10;
 5 ll p[maxn], a[maxn], t;
 6 void ex(ll a, ll b, ll &d, ll &x, ll &y){
 7     if(!b) d = a, x = 1, y = 0;
 8     else ex(b, a%b, d, y, x), y -= x*(a/b);
 9 }
10 ll solve(){
11     ll b = p[0], c = a[0], d, x, y, M;
12     for(int i = 1; i < t; ++i){
13         ll xx = a[i] - c;
14         ex(b, p[i], d, x, y);
15         if(xx % d){
16             return -1;
17         }
18         //cout<<x<<" "<<y<<"&&&"<<d<<endl;
19         x = (xx/d*x)%(p[i]/d);
20         //cout<<x<<"***"<<endl;
21         c = b*x+c, b = b/d*p[i], c %= b;
22         //cout<<c<<" "<<b<<endl;
23     }
24     return c <= 0 ? c+b : c;
25 }
26 int main(){
27     while(~scanf("%lld", &t)){
28         for(int i = 0; i < t; ++i){
29             scanf("%lld%lld", p+i, a+i);
30         }
31         printf("%lld\n", solve());
32     }
33     return 0;
34 }

 

 


----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

http://acm.hdu.edu.cn/showproblem.php?pid=1573

中文题

 

 

 

 

 1 #include <iostream>
 2 using namespace std;
 3 int n, m;
 4 int p[11], a[11];
 5 void ex(int a, int b, int &d, int &x, int &y){
 6     if(!b) d = a, x = 1, y = 0;
 7     else ex(b, a%b, d, y, x), y -= x*(a/b);
 8 }
 9 int solve(){
10     int b = p[0], c = a[0], d, x, y;
11     for(int i = 1; i < m; ++i){
12         ex(b, p[i], d, x, y);
13         int xx = a[i] - c;
14         //cout<<i<<" "<<a[i]<<" "<<c<<" "<<xx<<" "<<d<<endl;
15         if(xx%d){
16             return 0;
17         }
18         x = xx/d*x;
19         int w = p[i]/d;
20         x = (x%w+w)%w;
21         c +=x*b, b = b/d*p[i], c %= b;
22     }
23     c = (c > 0 ? c : c+b);
24     if(c > n) return 0;
25     else{
26         return max((n-c)/b, 0)+1;
27     }
28 }
29 int main(){
30     int t;
31     scanf("%d", &t);
32     for(int i = 0; i < t; ++i){
33         scanf("%d%d", &n, &m);
34         for(int j = 0; j < m; ++j){
35             scanf("%d", p+j);
36         }
37         for(int j = 0; j < m; ++j){
38             scanf("%d", a+j);
39         }
40         printf("%d\n", solve());
41     }
42     return 0;
43 }

 

 

 

 

只有不断学习才能进步!

 

wenbao与中国剩余定理(孙子定理)

原文:https://www.cnblogs.com/wenbao/p/5971406.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!