zoukankan      html  css  js  c++  java
  • 扩展中国剩余定理(EXCRT)小记

    前言

    其实(EXCRT)也并不像想象中那么难嘛。

    记得之前学的时候翻了好多博客都看不懂,现在可能是因为找到一篇通俗易懂的题解,一下就把这个算法搞明白了。

    同余方程

    给定一个如下形式的方程:

    [egin{cases} xequiv b_1( exttt{mod} a_1)\ xequiv b_2( exttt{mod} a_2)\ vdots\ xequiv b_n( exttt{mod} a_n) end{cases} ]

    (CRT)不同的是,(EXCRT)可以求解(a_1,a_2,...,a_n)不互质的情况。

    算法流程

    考虑我们从左向右扫,维护前(i-1)个同余方程的答案(ans)以及前(i-1)(a)的最小公倍数(M)

    现在我们要修改(ans)让它在依然满足前(i-1)个方程的同时满足第(i)个方程。

    发现只要我们给(ans)加上的数是(M)的倍数,它就必然依旧满足前(i-1)个方程。

    于是我们考虑列出一个不定方程:

    [ans+Mx=b_i+a_iy ]

    移项得到:

    [Mx-a_iy=b_i-ans ]

    这里由于我们并不需要知道(y)的具体值,其实也可以写成(Mx+a_iy=b_i-ans),主要看个人习惯。

    至于这个方程明显是可以(exgcd)求解的。

    然后只要给(ans)加上(Mx),更新(M)(lcm(M,a_i)),继续做下去就好了。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define LL long long
    #define N 100000
    using namespace std;
    int n;LL a[N+5],b[N+5];
    I LL QM(LL x,LL y,LL X) {LL k=(1.0L*x*y)/X,t=x*y-k*X;t-=X;W(t<0) t+=X;return t;}//快速乘
    I LL exgcd(LL x,LL y,LL& a,LL& b) {LL g;return y?(g=exgcd(y,x%y,b,a),b-=a*(x/y),g):(a=1,b=0,x);}//exgcd解不定方程
    int main()
    {
    	RI i;for(scanf("%d",&n),i=1;i<=n;++i) scanf("%lld%lld",a+i,b+i);
    	LL ans=b[1],M=a[1],g,A,B;for(i=2;i<=n;++i) A=B=0,g=exgcd(M,a[i],A,B),//ans维护答案,M维护lcm
    		ans+=QM(A,(b[i]-ans%a[i]+a[i])%a[i]/g,a[i]/g)*M,M*=a[i]/g,ans=(ans%M+M)%M;//更新ans和M,注意先更新M再取模
    	return printf("%lld
    ",ans),0;
    }
    
  • 相关阅读:
    zoj 3279 线段树 OR 树状数组
    fzu 1962 树状数组 OR 线段树
    hdu 5057 块状链表
    hdu3487 Play with Chain
    bzoj 1588营业额统计(HNOI 2002)
    poj2823 Sliding Window
    poj2828 Buy Tickets
    poj2395 Out of Hay
    poj3667 Hotel
    poj1703 Lost Cows
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/EXCRT.html
Copyright © 2011-2022 走看看