中国剩余定理

定理一:几个数相加,如果存在一个加数,不能被整数a整除,那么它们的和,就不能被整数a整除

定理二:两数不能整除,若除数扩大(或缩小)了几倍,而被除数不变,则其商和余数也同时扩大(或缩小)相同的倍数(余数必小于)除数

问题:今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何?

求解该问题的基本步骤

1、求出最小公倍数
        num=3*5*7=105
2、求各个数对应的基础数
(1)105/3=35         
     35/3=11.......2
     基础数35
(2)105/5=21  
     21/5=4......1
     根据定理2
     把1扩大3倍得到3,那么被除数也应扩大3倍
     21*3=63
     则基础数为63
    (63/5=12......3)
(3)105/7=15
     15/7=2......1
     根据定理2
     把1扩大2倍得到2,那么被除数也应该扩大3倍
     15*2=30
     则基础数为30
     (30/7=4......2)
(注意求得的基础数不一定就是正数)
3、把得到的基础数相加和
   35+63+30=128
4、减去最小公倍数num(在比最小公倍数大的情况下)
   x=128-105=23
则得出答案。满足题意的最小的数为23

解析

下面详细解释每一步的原因。

(1)最小公倍数就不解释了(这里讨论的都是两两互质的情况)

(2)观察求每个数对应的基础数时候的步骤,比如第一个。105÷3=35。
    35是除了当前这个数不能整除以外都能够被其他数(5和7)整除,
就是其他数的最小公倍数。相当于找到了最小的起始值,用它去除以3发现正好余2。那么这个基础数就是35。记住35的特征,可以整除其他数(5和7)但是不能被3整除,并且余数是2。
    再看下5对应的基础数。21是其他数(3和7)的最小公倍数,但是不能被5整除,用21除以5得到的余数是1,而要求的数除以5应该是余1的。所以余数被扩大,就得到了相应的基础数63。可以被其他数(3和7)整除但是被5除应该余3。
     同理,我们得到了第三个基础数23,那么他的特征就是:可以被其他数整除,但是不能被7整除,并且余数为2。

(3)第三步基础数加和,为什么要这样做呢?利用就是上面提到的定理1。

35+63+30=128。对于3来说,可以把63+30的和看作一个整体,因为他们都可以被3整除。看着上面写出的三个数的特征,运用定理1来说,就是在35的基础上加上一个可以被3整除的倍数,那么得到的结果依然还是满足原先的性质的,就是128除以同样还是余2的。同理,对于5还说,这个数被除之后会剩余3;对于7来说,被除之后剩余2。所以说,我们当前得到的这个数是满足题目要求的一个数。但是这个数是不是最小的,那就不一定了。

(1) 105/3=35   35=5*7   35/3=11......2

(2) 105/5=21   21=3*7   21/5=4......1
                        63/5=12......3

(3) 105/7=15   15=3*5   15/7=2......1
                        30/7=4......2

35+63+30=128

(63+30)/3=31   128/3=42......2
(35+30)/5=13   128/5=25......3
(35+63)/7=14   128/7=18......2

(4)应该不能确定是不是最小的数,这个时候就要用到他们的最小公倍数了。最小公倍数顾名思义,一定是一个同时被几个数整除的最小的一个数,所以减去它剩余下来的余数还是符合题意要求的。当然也同样可以运用定理1来解释,只不过是加法变成了减法,道理还是一样的。当然具体要不要减还是要看和num的大小关系的。

稍微的总结一下:就是已知m1,m2,m3是两两互质的正整数,求最小的正整数x,使它被m1,m2,m3除所得的余数分别是c1,c2,c3。孙子定理的思想便是线分别求出被其中数mi整除余1而被另外两个数整除的数Mi(i=1,2,3),则所求数之一的便是c1M1+c2M2+c3M3。由此我们可以得到n个两两互质数的情况。证明上面已经一步一步给出。

模板代码(不确定对不对,标记一下)

#include<stdio.h>
#include <iostream>
using namespace std;
//扩展欧几里得算法
int exgcd(int a,int b,int &x,int &y)
{
    int d;
    if(b==0)
    {
        x=1;y=0;
        return a;
    }
    d=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}
 //中国剩余定理 ,r[]存放余数 ,prime[]存放两两互质的数,len是组数
int Chinese_Remainder(int r[],int prime[],int len)
{
    int i,d,x,y,m,n=1,sum=0;
    //计算所以除数的积n,也是所以除数的最小公倍数
    for(i=0;i<len;i++)
        n*=prime[i];
    //计算符合所以条件的数
    for(i=0;i<len;i++)
    {
        m=n/prime[i];
//计算除去本身的所有除数的积m

        d=exgcd(prime[i],m,x,y);
//计算w[i]*x+m*y=gcd(w[i],m)的一个解y

        //累加整数解y的同时并不断对n取余,其利用公式:(a+b)%c=(a%c+b%c)%c
        sum=(sum+y*m*r[i])%n;
    }
    return (n+sum%n)%n;//满足所以方程的最小解
}
int main()
{
    int n,i;
    int prime[15],r[15];
    while (printf("请输入组数n:\n"),scanf("%d",&n)!=EOF)
    {
        printf("请依次输入每组的除数和余数:\n");
        for (i=0;i<n;i++)
        {
            scanf("%d%d",&prime[i],&r[i]);
        }
        //printf("%d\n",Chinese_Remainder(b,w,n));
        printf("符合条件的最小整数:%d\n\n",Chinese_Remainder(r,prime,n));
    }
    return 0;
}

 核心代码

int Chinese_Remainder(int r[],int prime[],int len)
{
    int i,d,x,y,m,n=1,sum=0;
    for(i=0;i<len;i++)
        n*=prime[i];
    for(i=0;i<len;i++)
    {
        m=n/prime[i];
        d=exgcd(prime[i],m,x,y);
        sum=(sum+y*m*r[i])%n;
    }
    return (n+sum%n)%n;
}

第二种模板

/*long long gcd(LL a,LL b)
{
    return b==0?a:gcd(b,a%b);
}*/
#include<cstdio>
#define ll long long
//扩展欧几里得算法 
void gcd(ll a,ll b,ll &d,ll &x,ll &y)
{
    if(b==0){
        d=a;
        x=1,y=0;
    }
    else{//else不能省略 
        gcd(b,a%b,d,y,x);
        y-=(a/b)*x;
    }
}
//中国剩余定理 
ll China(int n,ll *m,ll *a)
{
    ll M=1,d,y,x=0;
    for(int i=0;i<n;i++) M*=m[i];
    for(int i=0;i<n;i++){
        ll w=M/m[i];
        gcd(m[i],w,d,d,y);
        x=(x+y*w*a[i])%M;
    }
    return (x+M)%M;
}
ll m[15],a[15];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%lld%lld",&m[i],&a[i]);
    printf("%lld",China(n,m,a));
}

 

例: 一个住校生,家里每星期给他36元生活费。该生每天实际只用生活费5元,某天他小姨到学校看他并给了50元钱,他用此钱买了两本喜爱的课外读物花10元,买学习用具花2元,放假回家后说明情况并给家长交回55元。

问:该生带几个星期的生活费?实际在校住几天?一共有多少钱?花去多少钱?

HDU 1573 X问题

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 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值