중국 잉여 정리 (CRT)과 확장 (ExCRT)

중국 잉여 정리 CRT

유도

감안 \ N- (\) 번째 합동 식
\ [\ 좌측 \ {\ 시작 및 정렬 {X} 및 \ 당량 A_1 \ pmod에 m_1과 {} \\ X 및 \ 당량 A_2 \ pmod에 m_2 {}를 \\ ... X 및 \\ \ 당량 A_N \ M_n PMOD {} \ 배향 엔드 {} \ 오른쪽. \]
\ (m_1과, M_2, ... M_n \) 페어 질량

\ (M = \ {prod_ I = 1} ^ {N} m_i \) ,求\ (X \ 개조 M \)

이 문제에 대한 해결책은 구조이다.

우리는 최종의 형태로 대답 가정 \ (n \) 및 용어는 해당 용어의 반응 계수 각각 합동 식의 구조를 입력.

각 항목의 각 계수는 다른 식의 결과의 구성에 영향을주지 않도록, 적절한 수를 곱한 값에 대한 필요는, 각 항목에 대해 개별적으로 구성.

쉽게 구성 발생
\ [M_i = \ FRAC {M } {m_i} \]

물론이 숫자는 단지 아날로그 \ (m_i \) 와 동일하지 \ (0 \) , 다음 변경 계수가 다른 방정식없는 영향을 미칠 것이다.

이제 우리는 그 금형 희망 \ (m_i을 \) 의미에서 그 \ (A_I \) 하지만, 아래 마지막 남은 구조 \ (M_i \) . 승산 심플 조 \ (M_i \) 금형 \ (m_i는 \) 원의 의미를 반대로 \ (inv_ m_i {} (M_i) \) , 그래서 몰드 것을 \ (m_i는 \) 의 의미가된다 (\ 1 \) 다음 곱 (A_I \) \ 아웃 구축.

요약하면, 응답은
[\ sum_ {I = 1 \ } ^ {N} M_i inv_ m_i {} (M_i) A_I \ 개조 {M} \]

모듈로 주요 조건 보장하지만 그 \ (M_i \) 가 아닌 \ (0 \) 는 것을 보장하기 위해 \ (inv_ {m_i} (M_i가 ) \) 이 존재한다.

실현

모든 질문에 대부분의 \ (m_i \)는 소수, 역 찾을 수있다 \ (QPow을 \) 가 될 수 있습니다.

일반적인 경우를 들어, 라인에 exgcd.

보드 질문 : 루오 구 조충 돼지 P1495

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
using namespace std;
typedef long long ll;

namespace ExGcd{
    ll x,y;
    ll ExGcd(ll a,ll b){
        ll ans;
        if(a%b==0){
            x=0;y=1;ans=b;
        }else{
            ans=ExGcd(b,a%b);
            ll x1=x,y1=y;
            x=y1;y=x1-a/b*y1;
        }
        return ans;
    }
    bool SolveEqu(ll a,ll b,ll c){
        ll d=ExGcd(a,b);
        if(c%d!=0) return 0;
        x*=c/d;y*=c/d;
        x=(x%b+b)%b;
        y=(c-a*x)/b;
        return 1;
    }
}
ll Inv(ll a,ll m){
    ExGcd::SolveEqu(a,m,1);
    return ExGcd::x;
}

const ll CRTN=20;
namespace CRT{
    ll N;
    ll m[CRTN],a[CRTN];
    ll Sol(){
        ll ans=0,M=1;
        for(ll i=1;i<=N;i++) M*=m[i];
        for(ll i=1;i<=N;i++){
            ll Mi=M/m[i];
            ans=(ans+Mi*Inv(Mi,m[i])*a[i])%M;
        }
        return ans;
    }
}
int main(){
    using namespace CRT;
    scanf("%lld",&N);
    for(ll i=1;i<=N;i++)
        scanf("%lld%lld",&m[i],&a[i]);
    printf("%lld",Sol());
    return 0;
}

중국 잉여 정리의 ExCRT 확대

ExCRT와 CRT는 루카스 (함께 할 수 ExLucas 아무것도으로, 중요하지 않습니다

사실, 순수 추론의 관점에서, ExCRT은 (조금 그리워 할 수 있습니다

유도

브라운관 문제지만, 계수는 임의이며 서로 소가 필요하지 않습니다.

이 때, 우리는 역 요소의 존재를 보장 할 수 없습니다. 어떻게이 문제를 해결하기 위해?

두 방정식을 병합하는 방법을 고려한다. 우리는 병합 할 수있는 방법을 찾을 수 있다면, 우리는 동일 할 수있을 것입니다 \ (n \) 에 대한 답변을 얻을, 합병 차례로 방정식을.
\ [\ 좌 \ {을 시작 \
{} 배향 X 및 \ 당량 A_1 \ pmod에 m_1과 {} \\ X 및 \ 당량 A_2 \ pmod에 m_2 {} \ {단부 정렬} \ 권리. \] 불확실성으로 제거됨 congruences 방정식
\ [\ 좌측 \ {을 시작 \ {} 배향 및 X = + A_1 y_1 m_1와, X = \\ m_2 y_2 + A_2 \ 단부 {} 배향 \ 권리. \]

이에 수득
\ [y_1 m_1과 m_2 = + A_1 y_2 + A_2 \]

그냥 스타일을 만날 수있는 그룹을 찾을 \ (y_1 \)\ (y_2 \) , 역 계산 될 수있다 \ (X 축을 \) 합병을 달성하기 위해.

그리고 우리가 얻을 바이너리 방정식의 하나입니다, 당신은 exgcd 해결 사용할 수 있습니다.

표준 타입으로
\ [m_1과 y_1 - m_2 y_2 = A_2 - A_1 \]

솔루션은 원한다. 솔루션이 없을 경우 일치하는 식을 나타내는 아무런 해결책이 없다.

최종적 화학식 결합 얻어진
\ [X \ 당량 m_1과 y_1 + A_1 \ {pmod에 LCM (m_1과, m_2)} \]

실현

단주의해야 할 점은이 솔루션은 방정식을 해결 되었어야한다는 것입니다 \ ((m_1과는 -m_2, A_2-A_1) \) 하지만, 하드 ExGCD가 있으므로, 음수를 다루는 \ (m_2 \)\ (m_1와 \) . 우리가 사용하지 않기 때문에 \ (y_2을 \) , 분명히 거기에 영향을받지 않습니다.

보드 질문 : 익스프레스 정수에 poj2891 이상한 방법 또는 루오 구 P4777, 중국 잉여 정리를 확장 (EXCRT)

잡은 곱셈 버스트 LL 받기변경 너무 게으른

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
using namespace std;
typedef long long ll;

namespace ExGcd{
    ll x,y;
    ll ExGcd(ll a,ll b){
        ll ans;
        if(a%b==0){
            x=0;y=1;ans=b;
        }else{
            ans=ExGcd(b,a%b);
            ll x1=x,y1=y;
            x=y1;y=x1-a/b*y1;
        }
        return ans;
    }
    bool SolveEqu(ll a,ll b,ll c){
        ll d=ExGcd(a,b);
        if(c%d!=0) return 0;
        x*=c/d;y*=c/d;
        x=(x%b+b)%b;
        y=(c-a*x)/b;
        return 1;
    }
}
ll Gcd(ll a,ll b){
    if(a%b==0) return b;
    return Gcd(b,a%b);
}
namespace ExCRT{
    ll a1,m1;
    void Init(){
        a1=0;m1=1;
    }
    void Expand(ll a2,ll m2){
        ExGcd::SolveEqu(m1,m2,a2-a1);
        ll y1=ExGcd::x;
        ll mn=m1*m2/Gcd(m1,m2);
        a1=(m1*y1+a1)%mn;
        m1=mn;
    }
}
int main(){
    ll N;scanf("%lld",&N);
    ExCRT::Init();
    for(ll i=1;i<=N;i++){
        ll a,m;scanf("%lld%lld",&m,&a);
        ExCRT::Expand(a,m);
    }
    printf("%lld",ExCRT::a1);
    return 0;
}

추천

출처www.cnblogs.com/sun123zxy/p/crt.html