中国剩余定理

来源:互联网 发布:怎么执行php图片木马 编辑:程序博客网 时间:2024/06/17 09:14

《孙子算经》中有“物不知数”问题:“今有物不知其数,三三数之余二 ,五五数之余三 ,七七数之余二,问物几何?”答为“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  得解!




倒推:

a1 = 3, b1 = 2;

a2 = 5, b2 = 3;

a3 = 7, b3 = 2;

假如x符合题目的条件,即x%ai = bi, 求最小的x;


N = a1*a2*.....an;

设Ni对ai求余结果为1,即

N1 = 70 = 5 * 7 * k1(k1为任意整数), N1 % a1 == 1;

N2 = 21 = 3 * 7 * k2(k2为任意整数), N2 % a2 == 1;

N3 = 15 = 3 * 5 * k3(k3为任意整数), N3 % a3 == 1;


即Ni = a1 * a2 *......ai-1 * ai+1*......an * ki;

根据Ni % ai * ki == bi来确定ki的值


x = ((N1*b1) + (N2*b2) + .....+ (Nn*bn)) % N;


转换后为Ni = N / ai * ki;(ki 为任意整数)①

又因为Ni = ai * kki + 1;(kki为任意整数)②

将①和②联立计算得N / ai * ki + (-ai * kki) == 1 == gcd (N/ai, -ai);③

根据③式可以求出最小的ki,将所有Ni相加对N取余即可得出结果x;


void China (){    LL sum = 1, ans = 0, x, y, m;    for (int i=0; i<n; i++)        sum *= a[i];    for (int i=0; i<n; i++)    {        m = sum / a[i];        biggcd (m, a[i], x, y);///扩展欧几里得        ans = (ans + m*x*b[i]) % sum;    }    if (ans < 0) ans += sum;    printf ("%lld\n", ans);}


0 0
原创粉丝点击