中国剩余定理

中国剩余定理
Time Limit: 1000MS Memory Limit: 1000K
   

Description

《孙子算经》中有“物不知数”问题:“今有物不知其数,三三数之余二 ,五五数之余三 ,七七数之余二,问物几何?”答为“23”。
--------这个就是传说中的“中国剩余定理”。 其实题目的意思就是,n % 3 = 2, n % 5 = 3, n % 7 = 2; 问n是多少?
那么他是怎么解决的呢?
看下面:
题目中涉及 3, 5,7三个互质的数、
令:5 * 7 * a % 3 = 1; --------------> a = 2; 即5 * 7 * 2 = 70;
3 * 7 * b % 5 = 1; --------------> b = 1; 即3 * 7 * 1 = 21;
3 * 5 * c % 7 = 1; --------------> c = 1; 即3 * 5 * 1 = 15;
为什么要使余数为1:是为了要求余数2的话,只要乘以2就可以,要求余数为3的话,只要乘以3就可以!
( 因为题目想要n % 3 =2, n % 5 =3, n % 7 =2; )
那么:要使得n % 3 = 2,那么( 5 * 7 * 2 )*2 % 3 = 2;( 因为5 * 7 * 2 % 3 = 1 )
同理: 要使得n % 5 = 3,那么( 3 * 7 * 1 )*3 % 5 = 3;( 因为3 * 7 * 1 % 5 = 1 )
同理:要使得n % 7 = 2,那么( 3 * 5 * 1 )* 2 % 7 = 2;( 因为3 * 5 * 1 % 7 = 1 )
那么现在将( 5 * 7 * 2 )* 2和( 3 * 7 * 1 )* 3和( 3 * 5 * 1 )* 2相加会怎么样呢?我们知道
( 5 * 7 * 2 )* 2可以被5和7整除,但是%3等于2
( 3 * 7 * 1 )* 3可以被3和7整除,但是%5等于3
( 3 * 5 * 1 )* 2可以被3和5整除,但是%7等于2
那么即使相加后,%3, 5, 7的情况也还是一样的!
那么就得到一个我们暂时需要的数( 5 * 7 * 2 )* 2 +( 3 * 7 * 1 )* 3 +( 3 * 5 * 1 )* 2 = 233
但不是最小的!所有我们还要 233 % ( 3 * 5 * 7 ) == 23 得解!
如果你看懂了,接下来有个问题,假设a%w[1]=b[1],a%w[2]=b[2],···a%w[i]=b[i]···,其中b,w数组已知,w[i]>0且两两互质,求a。

Input

多组样例,每组样例包含三行
第一行一个整数N(0<N<10)
第二行N个正整数,表示b数组(0<=b[i]<w[i])
第三行N个正整数,表示w数组(1<w[i]<100)

Output

最小正整数a,独立一行

Sample Input

3
2 3 2
3 5 7

Sample Output

23


中国剩余定理的模板:
typedef long long ll;
void extend_Euclid(ll a, ll b, ll &x, ll &y)  
{  
    if(b == 0)  
    {  
        x = 1;  
        y = 0;  
        return;  
    }  
    extend_Euclid(b, a % b, x, y);  
    ll tmp = x;  
    x = y;  
    y = tmp - (a / b) * y;  
}  
ll CRT(ll a[],ll m[],ll n)  {  
    ll M = 1;  
    ll ans = 0;  
    for(ll i=1; i<=n; i++)  
        M *= m[i];  
    for(ll i=1; i<=n; i++)  {  
        ll x, y;  
        ll Mi = M / m[i];  
        extend_Euclid(Mi, m[i], x, y);  
        ans = (ans + Mi * x * a[i]) % M;  
    }  
    if(ans < 0) ans += M;  
    return ans;  
}  


上面的是扩展欧几里得算法,下面是求解最小符合要求的数。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
ll c[15],b[15];
void extend_Euclid(ll a, ll b, ll &x, ll &y)  
{  
    if(b == 0)  
    {  
        x = 1;  
        y = 0;  
        return;  
    }  
    extend_Euclid(b, a % b, x, y);  
    ll tmp = x;  
    x = y;  
    y = tmp - (a / b) * y;  
}  
ll CRT(ll a[],ll m[],ll n)  {  
    ll M = 1;  
    ll ans = 0;  
    for(ll i=1; i<=n; i++)  
        M *= m[i];  
    for(ll i=1; i<=n; i++)  {  
        ll x, y;  
        ll Mi = M / m[i];  
        extend_Euclid(Mi, m[i], x, y);  
        ans = (ans + Mi * x * a[i]) % M;  
    }  
    if(ans < 0) ans += M;  
    return ans;  
}  
int main(){
	ll n;
	while(scanf("%lld",&n)!=EOF){
		ll i,j;
		for(i=1;i<=n;i++)scanf("%lld",&c[i]);
		for(i=1;i<=n;i++)scanf("%lld",&b[i]);
		printf("%lld\n",CRT(c,b,n));
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值