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

中国剩余定理


以下内容摘自百度百科

例题解析
例一:一个数,除以5余1,除以3余2。问这个数最小是多少?
采用通用的方法:逐步满足法
把除以5余1的数从小到大排列:1,6,11,16,21,26,……
然后从小到大找除以3余2的,发现最小的是11.
所以11就是所求的数。
先满足一个条件,再满足另一个条件,所以称之为“逐步满足法”。
例二:一个数除以5余1,除以3也余1。问这个数最小是多少?(1除外)
特殊的方法:最小公倍法
除以5余1:说明这个数减去1后是5的倍数。
除以3余1:说明这个数减去1后也是3的倍数。
所以,这个数减去1后是3和5的公倍数。要求最小,所以这个数减去1后就是3和5的最小公倍数。即这个数减去1后是15,所以这个数是15+1=16.
例三:一个数除以5余4,除以3余2。问这个数最小是多少?
这种情况也可以用最小公倍法。
数除以5余4,说明这个数加上1后是5的倍数。
数除以3余2,说明这个数加上1后也是3的倍数。
所以,这个数加上1后是3和5的公倍数。要求最小,所以这个数加上1后就是3和5的最小公倍数。即这个数加上1后是15,所以这个数是15-1=14。
多个数的,比如3个数的,有时候其中两个可以用特殊法,那就先用特殊法,用特殊法求出满足两个条件的数后再用通用的方法求满足最后一个条件的数。
例四:有1个数,除以7余2.除以8余4,除以9余3,这个数至少是多少?
除以7余2的数可以写成7n+2。
7n+2这样的数除以8余4,由于2除以8余2,所以要求7n除以8余2。
7n除以8余2,7除以8余7,要求n除以8余6(乘数之余等于余数之乘),则n最小取6。
所以满足“除以7余2,除以8余4”的最小的数是7×6+2=44,
所有满足“除以7余2,除以8余4”的数都可以写成44+56×m。
要求44+56×m除以9余3,由于44除以9余8,所以要求56×m除以9余4。(加数之余等于余数之加)
56×m除以9余4,由于56除以9余2,所以要求m除以9余2(乘数之余等于余数之乘),则m最小取2。
所以满足“除以7余2,除以8余4,除以9余3”的最小的数是44+56×2=156。
例五:三三数之剩二,五五数之剩三,七七数之剩二。问物几何?
即,一个整数除以三余二,除以五余三,除以七余二,求这个整数。
除以3余2和处于7余2的数可以写成21n+2。
21n+2除以5余3,要求21n除以5余1。
21n除以5余1,21除以5余1,要求n除以5余1(乘数之余等于余数之乘),则n最小取1。
所以满足“除以3余2,除以5余3,除以7余5”的最小的数是21×1+2=23。
标准解法:先从3和5、3和7、5和7的公倍数中相应地找出分别被7、5、3除均余1的较小数15、21、70 ( 注释:此步又称为求"模逆"运算,利用扩展欧几里得法并借助计算机编程可比较快速地求得.当然,对于很小的数,可以直接死算 )。即
15÷7=2……余1,
21÷5=4……余1,
70÷3=23……余1.
再用找到的三个较小数分别乘以所要求的数被7、5、3除所得的余数的积连加,
15×2+21×3+70×2=233. (将233处用i代替,用程序可以求出)
最后用和233除以3、5、7三个除数的最小公倍数.
233÷105=2……余23,
这个余数23就是合乎条件的最小数.
例六:一个数被5除余2,被6除少2,被7除少3,这个数最小是多少?
题目可以看成,被5除余2,被6除余4,被7除余4 。看到那个“被6除余4,被7除余4”了么,有同余数的话,只要求出6和7的最小公倍数,再加上4,就是满足后面条件的数了,6X7+4=46。
下面一步试下46能不能满足第一个条件“一个数被5除余2”。不行的话,只要再46加上6和7的最小公倍数42,一直加到能满足“一个数被5除余2”。这步的原因是,42是6和7的最小公倍数,再怎么加都会满足“被6除余4,被7除余4”的条件。
46+42=88
46+42+42=130
46+42+42+42=172
例7:一个班学生分组做游戏,如果每组三人就多两人,每组五人就多三人,每组七人就多四人,问这个班有多少学生?
题目可以看成,除3余2,除5余3,除7余4。没有同余的情况,用的方法是“逐步约束法”,就是从“除7余4的数”中找出符合“除5余3的数”,就是再7上一直加7,直到所得的数除5余3。得出数为18,下面只要在18上一直加7和5得最小公倍数35,直到满足“除3余2”
4+7=11
11+7=18
18+35=53

HDU-1788        codeforces687-B 这两个题目是满足例二的情况的,都是余数相同的情况,只是输出这有点差别,所以都是求最小公倍数即可,代码如下:

/*
HDOJ 1788 Chinese remainder theorem again
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

long long gcd(long long a,long long b)
{
    if(b==0) return a;
    return gcd(b,a%b);
}
int main()
{
    long long n,k;
    while(scanf("%lld%lld",&n, &k)&&(n||k))
    {
        long long x, sum =  1;
        for (int i=0;i<n;i++)
        {
            scanf("%lld",&x);
            sum = sum / gcd(x, sum)*x;//求最小公倍数
        }
        cout<<sum-k<<endl;
    }
    return 0;
}


http://poj.org/problem?id=1006&lang=zh-CN

POJ可以简体中文竟然有的可以看,长见识了

讲解http://blog.csdn.net/lyy289065406/article/details/6648551


讲的太详细了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;


int main()
{
    int p,e,i,d;
    int ca = 1;
    while(~scanf("%d%d%d%d",&p,&e,&i,&d) && (p != -1|| e != -1 || i != -1 || d != -1))
    {
        printf("Case %d: the next triple peak occurs in ",ca++);
        int n = (5544*p + 14421*e + 1288*i - d + 21252) % 21252;
        if(n == 0)
            printf("21252 days.\n");
        else
            printf("%d days.\n",n);
    }
    return 0;
}

不过这样的更暴力好想一点,还让我知道了有中文版!
http://blog.csdn.net/eventqueue/article/details/50916951


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值