중국 잉여 정리 및 확장, 중국 잉여 정리

추측 TJOI2009

HDU 1573 X 문제



중국 잉여 정리의 CRT

중국 잉여 정리 동일한 선형 방정식을 해결하는데 사용된다.
\ [\ 시작 정렬 {} \ 좌측 \ {\ {시작 행렬 X} \ 당량 한 c_1 (MOD \ \, m_1과 \\) X \ 당량 C_2 (MOD \ \ m_2) \\ \\ X ... \ 당량 c_n (MOD \ \
, m_n) \ {단부 매트릭스} \ 오른쪽. \ 단부 정렬 {} \] 중국 잉여 정리오고있다.

의는 다음과 같은 식을 생각해 보자 :
. \ [\를} {시작 정렬 \ 왼쪽 \ {\}는 시작 {매트릭스 \ 당량 1 (MOD \, \, m_1과) \\ X_1 \ 당량 0 (MOD \, \, M_2을 X_1 \\) ... \\ X_1 \ 당량 0 (MOD \ \ m_n) \ {단부 매트릭스} \ 오른쪽. \ 좌측 \ {\ {시작 매트릭스 X_2} \ 당량 0 (MOD \ \, m_1과) \\ X_2 \ 1 당량 (MOD \ \, m_2) \\ \\ X_2 ... \ 당량 0 (MOD \ \ m_n) \ {단부 매트릭스} \ 오른쪽. \ 좌측 \ {는 \ {시작 행렬 x_n} \ 당량 0 (MOD \ \, m_1과 \\) x_n \ 당량 0 (MOD \ \ m_2) \\ ... \\ x_n \ 1 당량 (MOD \ \ m_n) \ {단부 행렬 .} \ 오른쪽 \ 단부 정렬 {
} \] 다음으로,에 \ (GCD (M1, M2, ..., m_n) \) 가 분명 할 때 다음과 같은 결론이 :

경우
\는 [\ 시작 \ {정렬} prod_ {I \ NEQ 1} m_i X_1 '& \ 당량 1 (MOD \ \, m_1과 \\) \ prod_ {I \ NEQ 2} m_i X_2'& \ 당량 1 (MOD을 \ \ m_2) \\ \
prod_ {내가 \ NEQ 않음} m_i x_n '{정렬} \ 당량 1 (MOD \ \ m_n) \\ \ 단부 \] 그래서
\ [\ 시작 {정렬} X_1 & = X_1은 '\ prod_ {I \는 1 NEQ} m_i \\ X_2 & = X_2'\ prod_ {난 NEQ 2 \} m_i \\ x_n & = x_n '\ prod_는 m_i \\ \ 단부 {난 NEQ 않음을 \} {정렬 } \]
그 최종 결과는
\ [X = \ sum_ {I
= 1} ^ nc_ix_i + K \ prod_ I = {1} ^ nm_i \] 다음 루틴을 작성하는 것이 좋다.

추측 TJOI2009

#include <bits/stdc++.h>
#define LL long long
using namespace std;

LL n;
LL A[ 20 ], B[ 20 ];
LL M, Ans, T[ 20 ];

LL QM( LL x, LL y ) {
    LL Ans = 0;
    for( ; y; y >>= 1, x = x * 2 % M ) 
        if( y & 1 ) Ans = ( Ans + x ) % M;
    return Ans;
}

void Expower( LL a, LL b, LL &x, LL &y ) {
    if( b == 0 ) {
        x = 1; y = 0; return;
    }
    Expower( b, a % b, y, x );
    y -= a / b * x;
    return;
}

LL INV( LL a, LL b ) {
    LL x, y;
    Expower( a, b, x, y );
    if( x < 0 ) x += b;
    return x;
}

int main() {
    scanf( "%lld", &n );
    for( LL i = 1; i <= n; ++i ) scanf( "%lld", &A[ i ] );
    for( LL i = 1; i <= n; ++i ) scanf( "%lld", &B[ i ] );
    for( LL i = 1; i <= n; ++i ) A[ i ] %= B[ i ];
    M = 1;
    for( LL i = 1; i <= n; ++i ) M *= B[ i ];
    for( LL i = 1; i <= n; ++i ) T[ i ] = QM( INV( M / B[ i ], B[ i ] ), ( M / B[ i ] ) );
    Ans = 0;
    for( LL i = 1; i <= n; ++i ) Ans = ( Ans + QM( A[ i ], T[ i ] ) ) % M;
    printf( "%lld\n", Ans );
    return 0;
}

확장, 중국 잉여 정리의 ExCRT

다만, 중국 잉여 정리는 상대적으로 프라임 타임을 모듈로 적용 언급. 계수가 상대적으로 소수가 아닌 경우, 우리는 확장, 중국 잉여 정리를 사용해야합니다.

ExCRT은 다음과 같이 작동합니다 :

먼저 우리는 2 개의 선형 합동 식을 준수
\ [\ 상기 시작 {X} \의 당량의 한 c_1과 (MOD \를 \ m_1과) X 및 \\ \ 당량 C_2 (MOD \ \ M_2) 배향 최종 \ {정렬 } \]
이 양식에 작성한다 :
\ [\ 배향 선두 {X} + 및 k_1m_1 = 한 c_1과 C_2 + = \\ 및 k_2m_2 배향 최종 \ {} \] X
동시 구한 후 :
\ [\ 배향 선두 { } 한 c_1 + k_1m_1 & = C_2 +
k_2m_2 \\ \ RIGHTARROW k_1m_1-k_2m_2 & = C_2 - 한 c_1 \ 단부 {정렬} \] 슈 페이 정리로부터 제조에 충분한 조건, 방정식 해결의 가능성이있다 \ (GCD (m_1과, m_2) | (C_2-한 c_1) \) .

이 경우, 우리는 얻을 수 있습니다 :
\ [\를 k_1 \ FRAC {m_1과} {GCD (m_1과, M_2)} {(가) 정렬} 시작 - K_2 \ FRAC {M_2} {GCD (m_1과, M_2)} = \ FRAC {c_2- 한 c_1} {GCD (m_1과, m_2 )} \\ \ RIGHTARROW 및 k_1 \ FRAC {m_1과} {GCD (m_1과, m_2)} \ 당량 \ FRAC {C_2 - 한 c_1} {GCD (m_1과, m_2)} \ \ ( 개조 \ \ \ FRAC { m_2} {GCD (m_1과, m_2)}) \\ \ RIGHTARROW 및 k_1 \ 당량 \ FRAC {C_2 - 한 c_1} {GCD (m_1과, m_2)} \ 시간 (\ FRAC {m_1과} {GCD (m_1과, m_2)}
) ^ {- 1} \ \ (MOD \ \ \ {FRAC m_2} {GCD (m_1과, m_2)}) \ {단부 정렬} \] 다음 \ (k_1 \) 위로 치환 \ (X = k_1m_1 \) 한 c_1 + 수득
\ [X \ 당량 \ {FRAC C_2 - 한 c_1} {GCD (m_1과, m_2)} \ 시간 (\ FRAC m_1과 {} {GCD (m_1과, m_2 )}) ^ {- 1}
\ 시간 m_1과 + C_2 \ \ (MOD \는 \ \ FRAC는 {m_2}가 {GCD는 (m_1과는 m_2는)}) \] 우리는 같은 형상을 가지고 \ (X의 \ 당량의 C \ \ (MOD \ \, m) \) 선형 합동 식. 그래서 반복적 인 솔루션이 될 수 있습니다.

HDU 1573 X 문제

#include <bits/stdc++.h>
#define LL long long
using namespace std;

const int Maxm = 20;

void Work();

int main() {
    int TestCases;
    scanf( "%d", &TestCases );
    for( ; TestCases; --TestCases ) Work();
    return 0;
}

int N, M, A[ Maxm ], B[ Maxm ];
struct equation {
    LL A, B;
};
equation T1, T2;

LL GCD( LL x, LL y ) {
    LL m = x % y;
    while( m ) {
        x = y; y = m; m = x % y;
    }
    return y;
}

void ExGCD( LL a, LL b, LL &x, LL &y ) {
    if( b == 0 ) {
        x = 1; y = 0; return;
    }
    ExGCD( b, a % b, y, x );
    y -= a / b * x;
    return;
}

LL Inv( LL a, LL b ) {
    LL x, y;
    ExGCD( a, b, x, y );
    if( x < 0 ) x += b;
    return x;
}

equation ExCRT( equation X, equation Y ) {
    LL Gcd = GCD( X.A, Y.A );
    if( ( Y.B - X.B ) % Gcd ) return ( equation ) { 0, 0 };
    LL A = X.A * Y.A / Gcd;
    LL B = Inv( X.A / Gcd, Y.A / Gcd ) * ( Y.B - X.B ) / Gcd % ( Y.A / Gcd ) * X.A + X.B;
    return ( equation ) { A, B };
}

void Work() {
    scanf( "%d%d", &N, &M );
    for( int i = 1; i <= M; ++i ) scanf( "%d", &A[ i ] );
    for( int i = 1; i <= M; ++i ) scanf( "%d", &B[ i ] );
    T1 = ( equation ) { A[ 1 ], B[ 1 ] };
    for( int i = 2; i <= M; ++i ) {
        T2 = ( equation ) { A[ i ], B[ i ] };
        T1 = ExCRT( T1, T2 );
        if( !T1.A ) {
            printf( "0\n" );
            return;
        }
    }
    if( T1.B < 0 ) T1.B += T1.A;
    if( T1.B > N ) {
        printf( "0\n" );
        return;
    }
    if( T1.B ) printf( "%d\n", ( int ) ( ( N - T1.B ) / T1.A + 1 ) ); 
    else printf( "%d\n", ( int ) ( N / T1.A ) );
    return;
}

추천

출처www.cnblogs.com/chy-2003/p/11458559.html