中国剩余定理

《孙子算经》有这么一道题:今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何。
就是说:一些东西,不知道有多少个,三个三个数剩两个,五个五个数剩三个,七个七个数剩两个,问这些东西最少有多少个。
《孙子歌诀》中给出了解法:三人同行七十稀,五树梅花廿一支,七子团圆正半月,除百零五便得知。
思路就是\(5*7=35\)\(35\)的倍数中能模\(3\)等于\(1\)的最小数是\(70\),同理\(3*7\mod{5}=1\),\(3*5\mod{7}=1\),接着\(70*2+21*3+15*2=233\),再将\(233\)\(105\)\(23\),最后23就是这些东西的最小个数。
原理:
\(70*2\mod{3}=2\)\(21*3\mod{3}=0\)\(15*2\mod{3}=0\) ==> \((70*2+21*3+15*2)\mod{3}=2\)\((70*2+21*3+15*2)\mod{105}\mod{3}=2\)
\(70*2\mod{5}=0\)\(21*3\mod{5}=3\)\(15*2\mod{5}=0\) ==> \((70*2+21*3+15*2)\mod{5}=3\)\((70*2+21*3+15*2)\mod{105}\mod{5}=3\)
\(70*2\mod{7}=0\)\(21*3\mod{7}=0\)\(15*2\mod{7}=2\) ==> \((70*2+21*3+15*2)\mod{7}=2\)\((70*2+21*3+15*2)\mod{105}\mod{7}=2\)
普遍思路:
\(\left\{\begin{matrix} m\mod a_{1}=b_{1} & & & & \\ m\mod a_{2}=b_{2} & & & & \\ …… & & & & \\ m\mod a_{n}=b_{n} & & & & \end{matrix}\right.\)
设$M=\prod_{i=1}^{n}a_{i} $,
设 $ n_{i} $ 是 \({M\div a_{i}}\) ,且\(n_{i}\mod a_{i}=1\)
最后的答案就是$\sum_{i=1}^{n}n_{i}*b_{i}\mod M $
证明:
\(n_{i}\mod a_{i}=1\) ==> \(n_{i}*b_{i}\mod a_{i}=b_{i}\)
n数组中除\(n_{i}\)外,其余的都可以被\(a_{i}\)整除。
所以\(\sum_{i=1}^{n}n_{i}*b_{i}\mod a_{i}=b_{i}\) ==> \(\sum_{i=1}^{n}n_{i}*b_{i}\mod M\mod a_{i}=b_{i}\)
代码:

#include<iostream>
#define int __int128
using namespace std;
int read(){
	int x=0,f=1;
	char a=getchar();
	while(a<'0'||a>'9'){
		if(a=='-')f=-1;
		a=getchar();
	}
	while(a>='0'&&a<='9'){
		x*=10;
		x+=a-'0';
		a=getchar();
	}
	return x*f;
}
int n;
int a[20],b[20];
void write(int a){
	if(a>9)write(a/10);
	putchar(a%10+48);
}
signed main(){
	n=read();
	for(int i=1;i<=n;i++){
		a[i]=read();
		b[i]=read();
	}
	int cnt=0;
	for(int i=1;i<=n;i++){
		int ans=1;
		for(int j=1;j<=n;j++){
			if(j!=i){
				ans*=a[j];
			}
		}
		int j;
		for(j=1;ans*j%a[i]!=b[i];j++);
		ans*=j;
		cnt+=ans;
	}
	int ji=1;
	for(int i=1;i<=n;i++){
		ji*=a[i];
	}
	cnt%=ji;
	write(cnt);
	return 0;
}

这里的\({n_{i}\div \left ( {M\div a_{i}}\right ) }\)可以用求逆元的方法求。

posted @ 2022-05-26 16:19  zzzzzz2  阅读(460)  评论(0)    收藏  举报