1. 程式人生 > >LUOGU P4777 【模板】擴展中國剩余定理(EXCRT)

LUOGU P4777 【模板】擴展中國剩余定理(EXCRT)

img lib display begin n) scan %d pen class

傳送門

解題思路

擴展 $crt?$,就是中國剩余定理在模數不互質的情況下,首先對於方程

? $\begin{cases} x\equiv a_1\mod m_1\\x\equiv a_2\mod m_2\end{cases}$

來說,可以將其寫為:



$\begin{cases} x=k_1*m_1+a_1\\x=k_2*m_2+a_2\end{cases}$



然後聯立方程:

? $k_1*m_1+a_1=k_2*m_2+a_2$

$\Leftrightarrow -k_1*m_1+k_2*m_2=a_1-a_2$

a這樣的話形式就很像$exgcd$ 了,可以$exgcd$求出$k_1‘*m_1+k_2‘*m_2=gcd(m_1,m_2)$的$k_1‘$了,然後若$(a_1-a_2)\%gcd(m_1,m_2)\neq 0$,則無解。然後讓方程兩邊同時乘$(a_1-a_2)/gcd(m_1,m_2)$,就可以求出$k_1$了,最後再帶入原式可以求出$x$的值,這個$x$記為$x_0$ ,即為滿足上面兩個方程的一個解,然後將這兩個方程

合並成一個方程:$x\equiv x_0\mod lcm(m_1,m_2)$,之後就可以一直合並就行了。



技術分享圖片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>

using namespace std;
const int MAXN = 100005;
typedef long long LL;
//typedef __int128 LL;

inline LL rd(){
    LL x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {f=ch==-?0:1;ch=getchar();}
    
while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-0;ch=getchar();} return f?x:-x; } int n; LL a[MAXN],b[MAXN],M,R; LL slow_mul(LL x,LL y,LL mod){ LL ret=0; for(;y;y>>=1){ if(y&1) ret=(ret+x)%mod; x=(x+x)%mod; } return ret; } LL exgcd(LL a,LL b,LL &x,LL &y){
if(!b) {x=1;y=0;return a;} LL now=exgcd(b,a%b,x,y); LL t=x;x=y;y=t-(a/b)*y; return now; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) a[i]=rd(),b[i]=rd(); M=a[1];R=b[1];LL x,y,d,now; for(int i=2;i<=n;i++){ d=exgcd(M,a[i],x,y); // if((R-r[i])%d!=0) puts("-1"); now=((R-b[i])%a[i]+a[i])%a[i]; x=slow_mul(x,now/d,a[i]);R-=M*x; M=M*(a[i]/d);R=(R%M+M)%M; } printf("%lld",(R%M+M)%M); return 0; }
View Code

LUOGU P4777 【模板】擴展中國剩余定理(EXCRT)