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


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

    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.
    ", 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
    ", 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.
    ", ++cnt, xx);
    22     //printf("%d
    ", 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
    ", 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
    ", 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
    ", solve());
    41     }
    42     return 0;
    43 }

    只有不断学习才能进步!

  • 相关阅读:
    Java 调用存储过程、函数
    Java BaseDao
    写好Java代码的30条经验总结
    15款Java程序员必备的开发工具
    Oracle基础 表分区
    Oracle基础 索引
    Oracle基础 触发器
    Oracle基础 程序包
    Oracle基础 自定义函数
    Oracle基础 存储过程和事务
  • 原文地址:https://www.cnblogs.com/wenbao/p/5971406.html
Copyright © 2020-2023  润新知