zoukankan      html  css  js  c++  java
  • 扩展中国剩余定理(简介)

    扩展中国剩余定理(普通线性同余不等式组)板子题

    对于中国剩余定理来说,每一个线性同余式所要求的的模数均为素数,这就在一定程度上限制了中国剩余定理的使用(但不能否认这是一个很有用而且很好用的算法)

    因此,我们需要找到一种对于模数不互质的线性同余式组的更普遍的求解算法

    扩展中国剩余定理构造求解

    • 对于一个线性同余方程组:

    • 我们首先假定一个数 (x) 为线性同余式组的前 (k-1) 个解,此时有 (M = lcm ( m1,m2,……,m_i ))

      则对于前 (k-1) 个线性同余式的通解为:(x + i imes M ( i in Z))

      那么对于第 (k) 个线性同余式,我们只需要找到一个数 (t) ,满足 (x + t imes M equiv a_k (mod m_k )) 即可

      整理一下,即可得到:(t imes M equiv a_k - x ( mod m_k )),对于整理得到的式子,我们就可以用扩展欧几里得算法求得 (t) 的值,再对答案进行累加即可

      所以,依次类推,对含有 (k) 个线性同余式的同余式组,只需使用 (k-1) 次扩展欧几里得算法即可求得答案

    下面放代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<math.h>
    #include<algorithm>
    #define ll long long
    using namespace std;
    
    const ll maxn=1e6+10;
    ll ai[maxn],bi[maxn];
    ll n;
    ll M,ans,bx;
    
    inline ll exgcd(ll a,ll b,ll &x,ll &y) //扩展欧几里得
    {
    	if(b==0)
    	{
    		x=1,y=0;
    		return a;
    	}
    	ll d=exgcd(b,a%b,x,y);
    	ll z=x;
    	x=y;
    	y=z-(a/b)*y;
    	return d;
    }
    
    inline ll multi(ll a,ll b,ll p)	 //龟速乘,避免乘法溢出 
    {
    	ll ret=0;
    	
    	while(b)
    	{
    		if(b&1)
    		{
    			ret=(ret+a)%p;
    		}
    		a=(a+a)%p;
    		b>>=1;
    	}
    	return ret;
    }
    
    inline ll crt()     			// excrt 求解 
    {
    	ll x,y,k,t;
    	
    	ll M=bi[1],ans=ai[1];		//初始时对 ans 和  M 进行预处理,将第一个同余式中的模数与余数赋给 M 和 ans ,作为第一组解 
    	
    	for(int i=2;i<=n;i++) 		//注意要进行 n-1 次循环 
    	{
    		ll a=M;
    		ll b=bi[i];
    		ll c=(ai[i]-ans%b+b)%b;  
    		ll g=exgcd(a,b,x,y);	//在进行扩展欧几里得算法时,求解的是 M * x + b[i] * y = gcd( M , b[i] ) 中 x 和 y 的值 , 并可顺便将 gcd( M , b[i] ) 求得 
    		if(c%g!=0) return -1; 	//目标解不能被 gcd ( M , b[i] ) 整除 , 说明该同余式无解 
    		bx=b/g;
    		x=multi(x,c/g,bx);
    		ans+=x*M;		//累加答案 
    		M*=bx;			//求 b[1] 到 b[i] 的 lcm
    		ans=(ans%M+M)%M;
    	}
    	
    	return (ans%M+M)%M;
    }
    
    int main(void)
    {
    	scanf("%lld",&n);
    	
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%lld%lld",&bi[i],&ai[i]);
    	}
    	
    	printf("%lld
    ",crt());
    	
    	return 0;
    }
    
  • 相关阅读:
    ubuntu环境下编译linux内核问题解决备忘
    Ubuntu 16.04 安装 arm-linux-gcc 交叉编译工具
    opus代码解析
    google的android工具常用下载路径
    opus在arm的嵌入式平台上的移植和开发
    OGG的孩子-有损音频编码opus
    ogg的孩子-无损音频编解码flac
    音频科普---oggs
    当初我为什么要去创业公司呢?
    python实现桶排序算法
  • 原文地址:https://www.cnblogs.com/jd1412/p/13359831.html
Copyright © 2011-2022 走看看