zoukankan      html  css  js  c++  java
  • 中国剩余定理

    给定(n)个形如(x equiv a_i(mod b_i))的同余方程,求出最小正整数解。

    模板题

    证明

    首先对于两个同余方程:
    (x equiv a_1(mod b_1))
    (x equiv a_2(mod b_2))
    我们可以进行一次“合并”操作,将上面两个方程合并为一个同余方程:
    (x equiv a_3(mod b_3))
    那么如何合并呢?首先很容易可以求出(b_3=lcm(b_1,b_2)),然后我们注意到(x equiv a_1(mod b_1)),那么(x)可以写成(k*a_1+b_1)的形式,然后枚举(k),直到满足(k*a_1+b_1 equiv a_2(mod b_2)),此时跳出循环。而注意到当(k)枚举到(a_2)的时候,再往后枚举就没有意义了,就会重复,所以如果此时还没有找到符合条件的解,就无解,退出循环即可。

    证明好像非常潦草,但其实证明并不重要。

    优化手段

    1.由于我们要在循环里枚举(a_2),所以一开始先判断(a_1)(a_2)的大小关系,如果(a_1)要更小,那么交换(a_1)(a_2)(b_1)(b_2)

    2.可以将(a_i)从大到小排序。(不懂为什么)

    代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define ll long long
    using namespace std;
    ll n,ans1,ans2;
    ll a[110],b[110];
    ll gcd(ll x,ll y){
    	if(y==0) return x;
    	else return gcd(y,x%y);
    }
    ll lcm(ll x,ll y){
    	return x/gcd(x,y)*y;
    }
    void merge(ll a1,ll b1,ll a2,ll b2,ll &a3,ll &b3){//合并两个同余方程
    	a3=lcm(a1,a2);
    	if(b1<b2){
    		swap(a1,a2);
    		swap(b1,b2);
    	}
    	for(int i=0;i<a2;i++){
    		if((b1+i*a1)%a2==b2){
    			b3=(b1+i*a1)%a3;
    		}
    	}
    }
    int main()
    {
    	scanf("%lld",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%lld%lld",&a[i],&b[i]);
    	}
    	ans1=1,ans2=0;
    	for(int i=1;i<=n;i++){
    		merge(ans1,ans2,a[i],b[i],ans1,ans2);
    	}
    	printf("%lld
    ",ans2);
    	return 0;
    }
    
  • 相关阅读:
    捋一下Redis
    docker 的简单操作
    opencv的级联分类器(mac)
    python日常
    pip安装显示 is not a supported wheel on this platform.
    字节流与字符流的区别详解
    请求转发和重定向的区别及应用场景分析
    Eclipse的快捷键使用总结
    Eclipse给方法或者类添加自动注释
    IntelliJ IDEA 连接数据库 详细过程
  • 原文地址:https://www.cnblogs.com/57xmz/p/14197309.html
Copyright © 2011-2022 走看看