考虑一个问题:一个整数除以3余2、除以5余3、除以7余2,求这个整数
part1
问题1:计算一个整数 x ,使得它满足除以3余2、除以5余3、除以7余2。
如果能够找到三个整数 x_1,x_2,x_3 ,使得:
x_1 除以3余2、除以5余0、除以7余0;
x_2 除以3余0、除以5余3、除以7余0;
x_3 除以3余0、除以5余0、除以7余2;
那么令 x=x_1+x_2+x_3 ,就很容易验证这时的 x 就满足除以3余2、除以5余3、除以7余2。
part2
问题1-1-1为:寻找整数 y_1 满足 y_1 除以3余1、除以5余0、除以7余0;
问题1-2-1为:寻找整数 y_2 满足 y_2 除以3余0、除以5余1、除以7余0;
问题1-3-1为:寻找整数 y_3 满足 y_3 除以3余0、除以5余0、除以7余1
这三个问题本质上是相同的。如果找到了 y_1,y_2,y_3 ,那么就可以取 x=2×y_1+3×y_2+2×y_3 。
part3
对于上述每个问题,就转化为求模逆元问题:(费马定理,或者拓展欧几里得定理)
part4
贴代码
C++
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll a[1010]={2,3,2},m[1010]={3,5,7};
ll qpow(ll x,ll n,ll mod){
ll res=1;
while(n){
if(n&1)res=res*x%mod;
n>>=1;
x=x*x%mod;
}
return res;
}
ll inv(ll x,ll mod){return qpow(x,mod-2,mod);}
ll CRT(ll n){
ll M=1,x=0;
for(int i=0;i<n;i++)cout<<m[i]<<' ';
for(int i=0;i<n;i++)M=M*m[i];
for(int i=0;i<n;i++)x=x+a[i]*inv(M/m[i],m[i])*(M/m[i]);
return x%M;
}
python
from Crypto.Util.number import *
# CRT 模板
a=[2,4,5] #记录余数
m=[3,5,7] #记录模
# n=len(a)=len(m)
def CRT(n):
M,x=1,0
for i in range(n):
M=M*m[i]
for i in range(n):
x=x+inverse(M/m[i],m[i])*(M/m[i])*a[i]
return x%M
print(int(CRT(3)))