table of Contents
Chinese Remainder Theorem CRT
The Chinese Remainder Theorem is used in solving linear equations of the same.
\ [\ Begin {aligned} \ left \ {\ begin {matrix} x \ equiv c_1 (mod \, \, m_1) \\ x \ equiv c_2 (mod \, \, m_2) \\ ... \\ x \ equiv c_n (mod \, \
, m_n) \ end {matrix} \ right. \ end {aligned} \] Chinese remainder theorem is coming.
Let's consider the following equations:
\ [\ the aligned the begin {} \ left \ {\} x_1 the begin {Matrix \ equiv. 1 (MOD \, \, m_1) \\ x_1 \ equiv 0 (MOD \, \, M_2 ) \\ ... \\ x_1 \ equiv 0 (mod \, \, m_n) \ end {matrix} \ right., \ left \ {\ begin {matrix} x_2 \ equiv 0 (mod \, \, m_1) \\ x_2 \ equiv 1 (mod \ , \, m_2) \\ ... \\ x_2 \ equiv 0 (mod \, \, m_n) \ end {matrix} \ right., \ left \ {\ begin {matrix } x_n \ equiv 0 (mod \ , \, m_1) \\ x_n \ equiv 0 (mod \, \, m_2) \\ ... \\ x_n \ equiv 1 (mod \, \, m_n) \ end {matrix .} \ right \ end {aligned
} \] then, in the \ (gcd (m1, m2, ..., m_n) \) when it is clear that the following conclusions:
If
\ [\ begin {aligned} \ prod_ {i \ neq 1} m_i x_1 '& \ equiv 1 (mod \, \, m_1) \\ \ prod_ {i \ neq 2} m_i x_2' & \ equiv 1 (mod \, \, m_2) \\ \
prod_ {i \ neq n} m_i x_n '& \ equiv 1 (mod \, \, m_n) \\ \ end {aligned} \] so
\ [\ begin {aligned} x_1 & = x_1 '\ prod_ {i \ neq 1} m_i \\ x_2 & = x_2' \ prod_ {i \ neq 2} m_i \\ x_n & = x_n '\ prod_ {i \ neq n} m_i \\ \ end {aligned } \]
then the final result is
\ [x = \ sum_ {i
= 1} ^ nc_ix_i + k \ prod_ {i = 1} ^ nm_i \] then the routine is better to write it.
#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;
}
Extended Chinese remainder theorem ExCRT
Just mentioned, Chinese remainder theorem applies to modulo relatively prime time. If the modulus is not relatively prime, then we need to use the extended Chinese remainder theorem.
ExCRT works like this:
First we observe two linear congruence equation:
\ [\ the aligned the begin {X} & \ equiv c_1 and (MOD \, \, m_1) X & \\ \ equiv c_2 (MOD \, \, M_2) \ the aligned End { } \]
we will write it in this form:
\ [\ the aligned the begin {X} + & k_1m_1 = c_1 and c_2 + = \\ X & k_2m_2 \ the aligned End {} \]
after simultaneous obtain:
\ [\ the aligned the begin { } c_1 + k_1m_1 & = c_2 +
k_2m_2 \\ \ Rightarrow k_1m_1-k_2m_2 & = c_2-c_1 \ end {aligned} \] Sufficient conditions prepared from Shu Pei theorem, equation solvability is \ (gcd (m_1, m_2) | (c_2-c_1) \) .
In this case, we can get:
\ [\ the begin {the aligned} & 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)} \ equiv \ frac {c_2-c_1} {gcd (m_1, m_2)} \, \, ( mod \, \, \ frac { m_2} {gcd (m_1, m_2)}) \\ \ Rightarrow & k_1 \ equiv \ frac {c_2-c_1} {gcd (m_1, m_2)} \ times (\ frac {m_1} {gcd (m_1, m_2)}
) ^ {- 1} \, \, (mod \, \, \ frac {m_2} {gcd (m_1, m_2)}) \ end {aligned} \] then \ (k_1 \) substituting back \ (x = k_1m_1 \) c_1 + afford
\ [x \ equiv \ frac { c_2-c_1} {gcd (m_1, m_2)} \ times (\ frac {m_1} {gcd (m_1, m_2 )}) ^ {- 1}
\ times m_1 + c_2 \, \, (mod \, \, \ frac {m_2} {gcd (m_1, m_2)}) \] we have got a shape such as \ (X \ equiv c \, \, (mod \, \, m) \) linear congruence equation. So iterative solution can be.
#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;
}