中国剩余定理(普通)模板+拓展中国剩余定理模板

本算法的步骤如下:

  1. 首先求得各个除数的最小公倍数
  2. 把最小公倍数除以当前除数,意为创造一个除了本除数意外其他所有除数都可以整除的数字。然后用这个数字去求得它在同余于当前除数的环境下的逆元,这个数字乘以逆元就相当于在此除数环境下同余于1。
  3. 最终答案加上上面的扩大余数倍的乘积结果,再进行取余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();
    }
}
  1. 首先特别确定第一个方程的解
  2. 由已解方程组的相关信息,利用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();
    }
}

 

posted @ 2019-08-17 23:35  完全墨染的樱花  阅读(143)  评论(0编辑  收藏  举报