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

    中国剩余定理

    定义: 中国剩余定理其实就是多个线性同于方程的方程组;举个例子,《孙子算经》中曾提到过这样一个问题: 有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何。 其实这就是一个经典的中国剩余定理的例子。

    算法流程:

    计算所有模的积n -----> 对于第 i 个方程:计算mi = n/ni -------> 计算mi在模ni的意义下的逆元1/mi -------> 计算ci = mi* (mi^-1)(不要对ni取模)得:

    [方程为一解为: ans = sum_{i=1}^{k}a_ic_i (mod n) ]

    代码实现:

    //式中m[i]为除数必须两两互质才能这么算,否则请看excrt算法
    //式中b[i]是除数, a[i]是余数
    void exgcd(int a,int b,int &x,int &y)
    {
        if(b==0){ x=1; y=0; return;}
        exgcd(b,a%b,x,y);
        int tp=x;
        x=y; y=tp-a/b*y;
    }
    
    int china()
    {
        int ans=0,lcm=1,x,y;
        for(int i=1;i<=k;++i) lcm*=b[i];		//计算n
        for(int i=1;i<=k;++i)
        {
            int tp=lcm/b[i];					//求m[i]
            exgcd(tp,b[i],x,y);					
            x=(x%b[i]+b[i])%b[i];				//x要为最小非负整数解
            ans=(ans+tp*x*a[i])%lcm;			//ai*ci ci=tp*x
        }
        return (ans+lcm)%lcm;
    }
    

    扩展中国剩余定理

    它与中国剩余定理不同之处在于:中国剩余定理中所有的模一定是两两互素的,二在excrt中:所有的模不一定两两互素。

    思路为求解k次exgcd即可:

    //a[i]和b[i]分别是余数和除数
    
    LL mul(LL a, LL b, LL mod){
        LL ans = 0 % mod;
        while(b){
            if(b & 1)	ans = (ans + a) % mod;
            a = (a + a) % mod;
            b >>= 1;
    	}
        return ans % mod;
    }
    LL exgcd(LL a, LL b, LL &x ,LL &y)
    {
        if(b == 0)	{x = 1; y = 0; return a;}
        LL gcd = exgcd(b, a % b, x, y);
        LL tp = x; x = y; y = tp - a / b * y;
        return gcd;
    }
    LL excrt()
    {
        LL m = b[1], ans = a[1];			//第1个的答案,然后往下递推
        for(int i = 2; i <= n; i++)
        {
            LL c = (a[i] - ans % b[i] + b[i]) % b[i];
            LL gcd = exgcd(m, b[i], x, y);
            if(c % gcd != 0) 	return -1; 		//无解
        	x = mul(x, c/gcd, b[i]);
       	 	ans += x * m;
        	m *= b[i] / gcd;
        	ans = (ans % m + m) % m;
    	}
    	return (ans % m + m) % m;
    }
    

    洛谷excrt模板题:

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long LL;
    const int maxn = 1e5 + 10;
    const int inf = 0x3f3f3f3f;
    int gcd(int a,int b)    { return b == 0 ? a : gcd(b, a % b); }
    
    LL n, a[maxn], b[maxn];
    LL x, y;
    LL mul(LL a, LL b, LL mod){
        LL ans = 0 % mod;
        while(b){
            if(b & 1)	ans = (ans + a) % mod;
            a = (a + a) % mod;
            b >>= 1;
    	}
        return ans % mod;
    }
    LL exgcd(LL a, LL b, LL &x ,LL &y)
    {
        if(b == 0)	{x = 1; y = 0; return a;}
        LL gcd = exgcd(b, a % b, x, y);
        LL tp = x; x = y; y = tp - a / b * y;
        return gcd;
    }
    LL excrt()
    {
        LL m = b[1], ans = a[1];			//第1个的答案,然后往下递推
        for(int i = 2; i <= n; i++)
        {
            LL c = (a[i] - ans % b[i] + b[i]) % b[i];
            LL gcd = exgcd(m, b[i], x, y);
            if(c % gcd != 0) 	return -1; 		//无解
        	x = mul(x, c/gcd, b[i]);
       	 	ans += x * m;
        	m *= b[i] / gcd;
        	ans = (ans % m + m) % m;
    	}
    	return (ans % m + m) % m;
    }
    
    int main()
    {
        scanf("%lld", &n);
        for(int i = 1; i <= n; ++i){
            scanf("%lld %lld", &b[i], &a[i]);       //除数和余数
        }
        printf("%lld
    ", excrt());
        system("pause");
    }
    
  • 相关阅读:
    docker 批量删除
    ML
    hdu 1465:不容易系列之一(递推入门题)
    sdut 2162:The Android University ACM Team Selection Contest(第二届山东省省赛原题,模拟题)
    sdut 2163:Identifiers(第二届山东省省赛原题,水题)
    hdu 2108:Shape of HDU(计算几何,判断多边形是否是凸多边形,水题)
    hrbustoj 1545:基础数据结构——顺序表(2)(数据结构,顺序表的实现及基本操作,入门题)
    hdu 1312:Red and Black(DFS搜索,入门题)
    hrbustoj 1429:凸多边形(计算几何,判断点是否在多边形内,二分法)
    poj 1113:Wall(计算几何,求凸包周长)
  • 原文地址:https://www.cnblogs.com/StungYep/p/12252598.html
Copyright © 2011-2022 走看看