Acwing---204. 表达整数的奇怪方式 (Java)_数学知识_中国剩余定理模板

原题链接

①. 题目

在这里插入图片描述

②. 思路

  • 中国剩余定理要求a1,a2,…,an两两互质
    在这里插入图片描述

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

③. 学习点

中国剩余定理

④. 代码实现

import java.util.Scanner;

public class Main {
    
    
	static long k1,k2;
	//扩展欧几里得模板
	static long gcd(long a,long b) {
    
    
		if(b==0) {
    
    
			k1=1;k2=0;
			return a;
		}
		long d=gcd(b,a%b);
		long tmp=k1;
		k1=k2;
		k2=tmp-a/b*k1;
		return d;
	}
	public static void main(String[] args) {
    
    
		Scanner sc = new Scanner(System.in);
		int n=sc.nextInt();
		long a1=sc.nextLong();
		long m1=sc.nextLong();
		boolean flag=true;
		while(n-->1) {
    
    
			long a2=sc.nextLong();
			long m2=sc.nextLong();
			//扩展欧几里得求最大公约数
			long d=gcd(a1,a2);
			long t=a2/d; //k1的取值范围 
			//k1*a1-k2*a2=m2-m1
			//根据扩展欧几里得k1=k1∗(m2−m1)/gcd(a1,a2)
			k1=k1*(m2-m1)/d; 
			if((m2-m1)%d!=0) {
    
    
				//无解
				flag=false;
				break;
			}
			k1=(k1%t+t)%t;//取k1+k( a2 / d )最小值  防止出现负数
			 //此时公式变形为x=( a1*k1+m1 )+( k*[a1,a2] ),k取任何整数,所以可以替换k1、k2、、
			m1=a1*k1+m1 ;
			//[]代表最小公倍数= 两个数乘积/两个数最大公约数
			a1=a1/d*a2;
		}
		if(flag) {
    
    
			 //因为每次都是两个式子合并,而且每个x=k*a+m,而维护到最后一次的时候公式里的 m1=a1*k1+m1,a1=a1/d*a2
			//所以到最后会合并成一个式子:x= m1(%a1) = k*a1+m1  。这时候让%a1移到左边 
			//变为m1 % a1 = x,此时结果就是取m1 % a1最小正整数
			System.out.println((m1%a1+a1)%a1);//(m1 % a1的最小正整数)
		}else {
    
    
			System.out.println(-1);
		}
	}

}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_45480785/article/details/113896423