本算法的步骤如下:
- 首先求得各个除数的最小公倍数
- 把最小公倍数除以当前除数,意为创造一个除了本除数意外其他所有除数都可以整除的数字。然后用这个数字去求得它在同余于当前除数的环境下的逆元,这个数字乘以逆元就相当于在此除数环境下同余于1。
- 最终答案加上上面的扩大余数倍的乘积结果,再进行取余LCM(要求最小整数解)
import java.util.*;
import java.math.*;
import java.io.*;
import java.text.*;
public class Main10
{
static long divisors[]=new long[50000];
static long reminders[]=new long[50000];
static long x,y,GCD;
public static long Secure_Multiply(long a,long b,long mod)
{
return(((a*b-(long)(((double)(a)*b+1e-6)/mod)*mod)%mod+mod)%mod);
}
public static long Extended_Eucild(long FirstNum,long SecondNum)
{
if(SecondNum==0)
{
x=1;y=0;
return FirstNum;
}
else
{
long tmpGCD=Extended_Eucild(SecondNum,FirstNum%SecondNum);
long tmp=x;
x=y;
y=tmp;
y-=(FirstNum/SecondNum)*x;
return tmpGCD;
}
}
public static long Chinese_reminder_theorem(long Limit)
{
long lcm=1,ans=0;
for(int i=1;i<=Limit;i++)
lcm*=divisors[i];
for(int i=1;i<=Limit;i++)
{
long tmp=lcm/divisors[i];
Extended_Eucild(tmp,divisors[i]);
x=(x%divisors[i]+divisors[i])%divisors[i];
long tmp1=Secure_Multiply(tmp,x,lcm);
ans=(ans+Secure_Multiply(tmp1,reminders[i],lcm))%lcm;
}
return (ans+lcm)%lcm;
}
public static void main(String args[])throws IOException
{
BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
String tmp=bf.readLine();
long n=Long.parseLong(tmp);
tmp=bf.readLine();
for(int i=1;i<=n;i++)
{
String tmps[]=tmp.trim().split(" ");
reminders[i]=Long.parseLong(tmps[i-1]);
}
tmp=bf.readLine();
for(int i=1;i<=n;i++)
{
String tmps2[]=tmp.trim().split(" ");
divisors[i]=Long.parseLong(tmps2[i-1]);
}
System.out.println(Chinese_reminder_theorem(n));
bf.close();
}
}
- 首先特别确定第一个方程的解
- 由已解方程组的相关信息,利用EXGCD解出未解方程
import java.math.*;
import java.nio.file.FileStore;
import java.io.*;
import java.text.*;
import java.util.*;
public class Main11
{
static long divisors[]=new long[950000];
static long reminders[]=new long[950000];
static long x,y;
public static long SecureMultiply(long a,long b,long mod)
{
long ans=(a*b)-(long)(((double)(a)*b+1e-5)/mod)*mod;
return ans>0?ans:ans+mod;
}
public static long Extended_Eucild(long FirstNum,long SecondNum)
{
if(SecondNum==0)
{
x=1;
y=0;
return FirstNum;
}
else
{
long tmpgcd=Extended_Eucild(SecondNum,FirstNum%SecondNum);
long tmp=x;
x=y;
y=tmp;
y-=(FirstNum/SecondNum)*x;
return tmpgcd;
}
}
public static long Extended_Chinese_reminder_theorem(long limit)
{
long ans=reminders[1],lcm=divisors[1];//第一个方程的解直接特判
for(int i=2;i<=limit;i++)
{
long parameter_a=lcm,parameter_b=divisors[i],parameter_c=(reminders[i]-ans%divisors[i]+divisors[i])%divisors[i];
//ax+by=c
long quotient=Extended_Eucild(parameter_a,parameter_b);
x*lcm+y*divisors[i]=(lcm,divisors)(因为如果除数间不一定互质的话这个最大公约数不一定是1)
if(parameter_c%quotient!=0)(如果不是倍数关系则不能得解)
return -1;
else
{
x=SecureMultiply(x,parameter_c/quotient,parameter_b/quotient);//把解扩大相应倍数
ans+=x*lcm;//更新答案
lcm=lcm*(parameter_b/quotient);//lcm扩大相应倍数
ans=((ans)%lcm+lcm)%lcm;
}
}
return ((ans)%lcm+lcm)%lcm;
}
public static void main(String args[])throws IOException
{
BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
//System.out.println(SecureMultiply(5, 6, 29));
String tmp=bf.readLine();
int totality=Integer.parseInt(tmp);
for(int i=1;i<=totality;i++)
{
tmp=bf.readLine();
String tmps[]=tmp.trim().split(" ");
divisors[i]=Long.parseLong(tmps[0]);
reminders[i]=Long.parseLong(tmps[1]);
}
System.out.println(Extended_Chinese_reminder_theorem(totality));
bf.close();
}
}