(擴展)中國剩餘定理(模板)

中國剩餘定理:猜數字

求解下列同餘方程組(模數互質)

{xa1 ( mod m1 )xa2 ( mod m2 )xan ( mod mn)\begin{cases} x \equiv a_1 \ (\ mod \ m_1\ )\\ x \equiv a_2 \ (\ mod \ m_2\ )\\ \quad \vdots\\ x \equiv a_n \ (\ mod \ m_n) \end{cases}

構造法
令:lcm=i=1nmi\displaystyle lcm=\prod\limits_{i=1}^{n}{m_i}Mi=lcmmi\displaystyle M_i=\frac{lcm}{m_i}x=inv(Mi,mi)x=inv(M_i,m_i)

則:ans=i=1naix\displaystyle ans=\sum\limits_{i=1}^{n}{a_i*x}

#include "bits/stdc++.h"
#define hhh printf("hhh\n")
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
inline ll read() {ll x=0,f=1;char c=getchar();while(c!='-'&&(c<'0'||c>'9'))c=getchar();if(c=='-')f=-1,c=getchar();while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();return f*x;}
 
const int maxn = 3e5+7;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;

ll exgcd(ll a, ll b, ll &x, ll &y) {
    if(!b) { x=1, y=0; return a; }
    ll ans=exgcd(b,a%b,y,x); y-=a/b*x;
    return ans;
}

ll a[maxn], b[maxn];

int main() {
    int n=read();
    for(int i=1; i<=n; ++i) a[i]=read();
    ll lcm=1;
    for(int i=1; i<=n; ++i) b[i]=read(), a[i]=(a[i]%b[i]+b[i])%b[i], lcm*=b[i];
    ll ans=0, x, y;
    for(int i=1; i<=n; ++i) {
        ll tmp=lcm/b[i];
        exgcd(tmp,b[i],x,y);
        x=(x%b[i]+b[i])%b[i];
        ans=(ans+__int128(a[i])*x%lcm*tmp%lcm)%lcm; //__int128處也可以改爲慢速乘
    }
    printf("%lld\n", ans);
}

擴展中國同餘定理

處理模數不一定互質的情況

思路:不斷合併同餘方程

合併策略:

令:g=(m1,m2)m=lcm(m1,m2)g=(m_1,m_2),m=lcm(m_1,m_2)

a=(inv(m1g,m2g)a2a1g)%\displaystyle a=\left(inv\left(\frac{m_1}{g},\frac{m_2}{g}\right)*\frac{a_2-a_1}{g}\right)\%m2gm1+a1\displaystyle \frac{m_2}{g}*m_1+a_1 ( mod m )(\ mod \ m \ )

詳細證明

#include "bits/stdc++.h"
#define hhh printf("hhh\n")
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
using namespace std;
typedef long long ll;
typedef __int128 lll;
typedef pair<int,int> pr;
inline int read() {int x=0,f=1;char c=getchar();while(c!='-'&&(c<'0'||c>'9'))c=getchar();if(c=='-')f=-1,c=getchar();while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();return f*x;}

const int maxn = 3e5+7;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;

int n;
ll a[maxn], b[maxn];

lll exgcd(lll a, lll b, lll &x, lll &y) {
    if(!b) { x=1, y=0; return a; }
    lll ans=exgcd(b,a%b,y,x); y-=a/b*x;
    return ans;
}

ll exchina() {
    lll A=0, B=1, x, y; //A表示餘數,B表示模數;a,b同理
    for(int i=1; i<=n; ++i) {
        lll g=exgcd(B,b[i],x,y);
        lll Bg=B/g, bg=b[i]/g;
        exgcd(Bg,bg,x,y);
        x=(x%bg+bg)%bg;
        lll lcm=Bg*b[i];
        if((a[i]-A)%g) return -1;
        A=(((a[i]-A)/g*x%bg*B+A)%lcm+lcm)%lcm;
        B=lcm;
    }
    return ll(A);
}

int main() {
    n=read();
    for(int i=1; i<=n; ++i) scanf("%lld%lld", &b[i], &a[i]);
    printf("%lld\n", exchina());
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章