• 拓展中国剩余定理(ex_crt)


    一般来讲,crt(中国剩余定理)比较常见,而ex_crt(拓展中国剩余定理)不是很常用

    但是noi 2018偏偏考了这么个诡异的东西...

    所以这里写一个ex_crt模板

    模型:

    left{egin{matrix} x1 & equiv & b1 & mod & a1\ x2 & equiv & b2 & mod & a2\ ......\ xn & equiv & bn & mod & an end{matrix}
ight.

    求一个x满足上述方程,其中a1,a2...an不一定互质

    解法:

    设存在一特解x0满足前k个方程组,且LCM(a1,a2...ak)=M

    则前k个方程的通解x=x0+k·M(k∈Z)

    这是很显然的,因为M equiv 0 mod ai (1<=i<=k)

    那么第k+1个方程等价于:求使egin{matrix} x0 + & t*M & equiv & bk+1 & mod ak+1 end{matrix}t

    这显然可以使用ex_gcd求解(移项即可)

    那么剩余部分就简单了:不断维护一个x0,最后返回x0即可

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #define ll long long
    using namespace std;
    ll n;
    ll a[100005];
    ll b[100005];
    ll pow_add(ll x,ll y,ll mod)
    {
        ll ans=0;
        while(y)
        {
            if(y%2)
            {
                ans+=x;
                ans%=mod;
            }
            y/=2;
            x+=x;
            x%=mod;
        }
        return ans;
    }
    ll gcd(ll x,ll y)
    {
        if(y==0)
        {
            return x;
        }
        return gcd(y,x%y);
    }
    void ex_gcd(ll a,ll b,ll &x,ll &y)
    {
        if(b==0)
        {
            x=1;
            y=0;
            return;
        }
        ex_gcd(b,a%b,x,y);
        ll t=x;
        x=y;
        y=t-(a/b)*x;
    }
    ll ex_crt()
    {
        ll M0=a[1];
        ll ans=b[1];
        for(int i=2;i<=n;i++)
        {
            ll r=gcd(M0,a[i]);
            ll bb=((b[i]-ans)%a[i]+a[i])%a[i];
            if(bb%r)
            {
                return -1;
            }
            bb/=r;
            ll M=M0/r;
            ll aa=a[i]/r;
            ll x,y;
            ex_gcd(M,aa,x,y);
            x=pow_add(x,bb,aa);
            ans+=x*M0;
            M0*=aa;
            ans=(ans%M0+M0)%M0;
        }
        return (ans%M0+M0)%M0;
    }
    int main()
    {
        scanf("%lld",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld%lld",&a[i],&b[i]);
        }
        printf("%lld
    ",ex_crt());
        return 0;
    }
  • 相关阅读:
    GridView中checkbox实现全选[转]
    go 格式化秒 running
    mysql 聚簇索引和非聚簇索引 running
    go context上下文取消 running
    go reflect running
    time.ticker running
    go 数据结构与算法之二分查找 running
    mysql 联合索引最左前缀匹配原则 running
    es 修改 mapping 字段类型 running
    linux 查看虚拟机网卡命令 running
  • 原文地址:https://www.cnblogs.com/zhangleo/p/9732560.html
Copyright © 2020-2023  润新知