1.中国剰余定理(CRT)
1.1問題の導入
- 与えられた合同式、フォーム
\ [\開始{ケース} X \当量A_1 \ PMOD {P_1} \\ X \当量A_2 \ PMOD {P_2} \\ \ドット\\ X \当量A_N \ PMOD {P_N} \\ \端{ケース} \ ]
- 前記\(P_I \)ペアごとの品質。
式1.2のソリューション
- 我々は覚えて\(M = \ prod_ = {I}。1 np_i ^ \)、\ (M_I = \ {P_I FRAC {M}} \) 。
- 我々は持って解決assume've \(X_0 \) 、その後、\(X_0 +キロ(K \ mathbb Z \で)\) はっきり方程式の解です。
- すなわち約構成する全てのソリューション\(M \)残留カテゴリ。
- そこでのみ必要\([0、M)\ ) の溶液整数。
- 中国の剰余定理は、結論を与えるこの式\([0、M)\ ) ユニークな溶液中に存在しているが。
ソリューション1.3式
- のは、解決策を見つける方法を考えてみましょう。
- 我々は考える(\ n)は\番目の方程式、\(I \)方程式グループ
\ [\ {ケースを}開始X_I \当量0 \ PMOD {P_1} \\ X_I \当量0 \ PMOD {P_2} \\ ~~~~〜~~〜\ドット\\ X_I \当量a_iを\ PMOD {P_I} \\ ~~~~~ ~~〜\ドット\\ X_I \当量0 \ PMOD {P_ {N-1}} \\ X_I \当量0 \ PMOD {P_N} \\ \端{ケース} \]
- 次に、\(\ sum_ {I 1 = ^ nx_i \}) 溶液にします。
- のみに必要\(M \)を法として得\([0、N)\ ) その中に特別なソリューション。
- 考えてみましょう\(X_I \)どのように需要。
- 私たちは方程式のシステムを考えてみましょう
\ [\ {ケースを}開始Y_I \当量0 \ PMOD {P_1} \\ Y_I \当量0 \ PMOD {P_2} \\ ~~~~〜~~〜\ドット\\ Y_I \当量1 \ PMOD {P_I} \\ ~~~~~ ~~〜\ドット\\ Y_I \当量0 \ PMOD {P_ {N-1}} \\ Y_I \当量0 \ PMOD {P_N} \\ \端{ケース} \]
- その後、我々は作ることができます\(X_I = a_iy_i \) 。
- 以来|(Y_I(J \ NEQ I)\ p_j)\、および\(P_I \) 、互いに素任意の2つの間のように、\(M_I \)型の中\(P_I \)私たちができるような意味で逆の要素があります直接注文\(Y_I M_I = \タイムズM_I ^ { - }。1 \)、\ (M_I ^ { - }。1 \)は逆元を表します。
- 逆に、ケースとしてある可能性があり(exgcd \)\またはフェルマーの小定理要件。
- 所以\(X_I = M_I \回M_I ^ { - 1} \回a_iを\) 。
- だから、- (1 \タイムズa_iを\。{}。ANS = \ sum_ = {I} 1 ^ nm_i \タイムズM_I ^)\、オーバーフローを防ぐために、我々は唯一死んする必要があります\(M \)センス動作に作られました。
- なお、\(CRT \)と\(exCRT \)時々 、乗算、この問題を参照してくださいに対処する方法にオーバーフローする可能性[ヒント] O(1)迅速な乗算- changle_cyx。
金型で1.4ソリューション\(M \)の意味でユニーク
- 我々は証明次に、その金型内の溶液\(M \)の意味でユニーク。
- すなわち2つの解が存在しないことを証明する(X_0、X_1 \)\、そう(M \ X_1 NMID-X_0 \)\。
- 背理法:
- 注文が\(X_0 \)元の方程式の特殊解を表し、別の解決策がある\(D X_0 + \)ので、(M \ NMID D \)\。
- 则\(\ I \ [1、N]で、P_I \ NMID D \存在する)、即\(D \ない\当量0 \ PMOD {P_I} \) 。
- \(X_0 \)利用可能な元の方程式の解である(ans_0 \当a_iを\ PMOD {P_I} \)\。
- だから(X_0 + D \ \当量a_iをPMOD {P_I} \ \ていない)\、(D X_0 + \) \ 解決策ではないオリジナルの方程式、および仮定に反します。
- QED。
- だから我々は、中国の剰余定理を得ます。
- 中国の剰余定理にこのユニークな幅広いアプリケーションは、2つの例は、セクション3に記載されています。
中国の剰余定理(exCRT)を展開2。
2.1問題の導入
- 方程式を解くために、中国剰余定理は二十から二互いに素を法。
- モジュラスが互いに素二十から二次方程式を満たしていないのでために、どのようにそれを解決するには?
- 即求解
\ [\ {ケースを}開始X \当量A_1 \ PMOD {P_1} \\ X \当量A_2 \ PMOD {P_2} \\ \ドット\\ X \当量A_N \ PMOD {P_N} \\ \端{ケース} \] - どこに\(P_I \)特別な制約。
式2.2のソリューション
- 必ずしも解ける方程式は、我々は、溶液プロセスでの方法を決定することができます。
- 我々は覚えて\(M_I = \ {テキスト} LCM(P_1、P_2、\ DOTS、P_I)\)、\ (M = \ {テキスト} LCM(P_1、P_2、\ DOTS、P_N)\) 。
- 我々は特定の解決策を得ると仮定(X_0 \)\、そう\(X_0 +キロ(K \ mathbb Z)\ \で) ソリューションは、式です。
- ソリューションアウト\(X \)も、残りのクラスの1つです。
- 方程式が解を持つ場合1.4と同様の証拠、我々はまだ、金型における方程式の解を得ることができます(\ M)\意味でユニーク。
式2.3のソリューション
- 彼らは互いに素でないので、我々はそれを行うためにプライムようにすることはできません理由は、私たちは逆数が存在しないかもしれない必要がある、場合です。
- 私たちは、背面にフロントマージする1つの方程式ずつ検討してください。
- 私たちは、最初にソリューションを想定し\(I \)の方程式、我々が作る(\ X_Iを)\表し、Aモジュロ\(M_I \)の意味でのユニークなソリューション。
- 最初の場合は\(1 \)の方程式、我々は直接作る(X_1 = A_1 \)\。
- 以下のための最初の(私は、(i> 1)\ \) 式、我々は最初に知っている\(I-1 \)の方程式の一般解のための\(X_ {I-1} + km_ {I-1}(K \で\ Z-mathbb)\) 。
- だから今我々が最初に追加します\(I \)の限界方程式\を(X- \当量a_iを\ PMOD P_I} {\) 。
- そして、最初の\(I \)の連立方程式の後の式と等価です
\ [X_ {I-1} + km_ {I-1} \当量a_iを(MOD〜P_I)\]
- 形式で書かれている不定方程式
\ [M_ {I-1} K + p_iy = a_iを-X_ {I-1} \]
- 次に、ユークリッドアルゴリズム(拡張\(exgcd \)この式で溶液)。
- 存在する場合、\(I \)ので、この方程式が解を持たないこと、すなわち、\((I-m_Low {} 1は、P_I)\ a_iをNMID。1-I-X_ {} \)も手段は方程式のセット全体は、解がないこと。
- そうでない場合は特別な溶液解くせる\(K \)型にアクセス\(FRAC {P_I} {( M_ {I-1}、P_I)} \ \) の意味で、そして場合でも、一意の解を(K \)\の\ (\ FRAC {P_I} {( M_ {I-1}、P_I)} \) モジュロ。
- 次に、取得し(1. 1-m_Low {I} K \。I-X_I = X_ {+})\、また作る\(X_I \)の\(M_I \)にモジュロ。
- 最後に\(x_nに関する\)答えがあります。
- テンプレートの質問:羅区P4777 -拡張中国の剰余定理(EXCRT)
#include <cmath>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
template <class T>
inline void read(T &x)
{
static char ch;
while (!isdigit(ch = getchar()));
x = ch - '0';
while (isdigit(ch = getchar()))
x = x * 10 + ch - '0';
}
typedef long long s64;
const int MaxN = 1e5 + 5;
int n;
s64 p[MaxN], a[MaxN], pre_lcm[MaxN];
inline s64 qmul(s64 b, s64 p, const s64 &mod)
{
b = (b % mod + mod) % mod;
p = (p % mod + mod) % mod;
s64 res = 0;
for (; p; p >>= 1, (b = b + b) > mod ? (b -= mod) : 0)
if (p & 1)
{
res = res + b;
if (res >= mod)
res -= mod;
}
return res;
}
inline s64 ex_gcd(const s64 &a, const s64 &b, s64 &x, s64 &y)
{
if (!b)
return x = 1, y = 0, a;
s64 res = ex_gcd(b, a % b, y, x);
y -= a / b * x;
return res;
}
inline s64 solve_equ(const s64 &a, const s64 &b, const s64 &c)
{
s64 x, y;
s64 d = ex_gcd(a, b, x, y);
return qmul(x, c / d, b / d);
}
int main()
{
read(n);
for (int i = 1; i <= n; ++i)
read(p[i]), read(a[i]);
pre_lcm[1] = p[1];
for (int i = 2; i <= n; ++i)
pre_lcm[i] = p[i] / std::__gcd(pre_lcm[i - 1], p[i]) * pre_lcm[i - 1];
s64 x = a[1];
for (int i = 2; i <= n; ++i)
{
s64 k = solve_equ(pre_lcm[i - 1], p[i], a[i] - x);
x = x + qmul(pre_lcm[i - 1], k, pre_lcm[i]);
if (x >= pre_lcm[i])
x -= pre_lcm[i];
}
std::cout << x << std::endl;
return 0;
}
3.簡単なアプリケーション中国剰余定理
我々は(dalaoは、Dはありません)、2つの非常に非常に非常に簡単な例を与えます。
3.1オイラー関数は、証拠の乗法関数であります
- オイラー関数\(\ varphi(N)= \ sum_ {I} ^ N-1 = [I \ N-PERP] \) 、すなわち\(1 \)の\(\ N-)と\(N- \)プライム番号の数。
- オイラー関数は、乗法関数です。
- もし\(P \ PERP Q \) 、その後、\(\ varphi(PQ)= \ varphi(P)\ varphi(Q)\) 。
- 証明は、中国剰余定理の観点から、以下の通りであります:
- 我々は、セット(A \)\表す(1 \)\に\(P \)と(P \)\なる素数の集合、\(B \)を表し(1 \)\に(Q \ \ )と\(Q \)なる素数の集合、\(C \)を表す(1 \)\に\(PQ \)と(PQ \)\素数の組。
- 以来\(P \ PERP Q \) 、そう\(I \ PERP PQ \ Leftrightarrow I \ PERP P とI \ PERP Q \) 。
- 減法は、我々が知っている、除去\((N、M)=(N、M + KN)、K \で\ mathbb Z \) 。
- 上記の結論と組み合わせることで、我々は得ることができます
- 中国の剰余定理、我々はそれぞれのために持っている\(A \ Bで、B \におけるA \) 、我々は、合同式を得ることができる
{ケース} X開始\ [\ \当量A(MOD〜P)\\ Xを\当量B(MOD〜Q) \端{ケース} \] - ユニーク溶液\(X \)明らかに、および\([1、PQ] \ ) ではないの存在下で\(X \) 、そう\(Xは\)二つの異なる合同の方程式の解であります。
- したがって、私たちはできる(A \ Bタイムズ\)\(デカルト積)と\(Cを\)との間に全単射を確立します。
- 従って設定\(C \)の要素の数が等しくなるように設定されている\(A \)とセット\(B \)の要素の数の積。
- QED。
特別なトピックの数を解く3.2モジュラス
- 古典的なトピックを与えるために:BZOJ1951 [SDOI2010]古代豚の文化
- タイトル効果:シーク\(G ^ {\ sum_ {D |} N-N-C_ {D}} ^ {} \ MOD P(P = 999 911 659、N-、G \ ^ LE10 9)\)。
- 我々はことを知っています\(pは\)素数です。
- これは特別な何ですが、私はあなたには、トピックの最も数を尋ねると確信していますモジュラスそれが素数でないでしょうか??
- しかし、あなたはそれを見つける\(G \)インデックスは正確な値を直接得ることができず、大規模です。
- オイラーの定理、我々が知っている\(^ A B \当量A ^ B {\%\ varphi(P)}(〜MOD P)、A \ PERP P \) 。
- 場合は、\ |(P G \) 、答えは(0 \)\。
- それ以外の場合は、\(G \ P-PERP \) 、私たちは、オイラーの定理により解決することができます。
- Googleのインデックスの必要性だけ取るです| \(\ sum_ {N D C_ {n}は^} 、{D} \ MOD \ varphi(P)\) 、すなわち、\(\ sum_ {D | N } C_ {n}は^ D} {\ MOD 999 911 658 \) 。
- 今、私たちが直接あれば質問は、ある\(ルーカス\)定理を解決するために、弾性係数の条件を満たしていない素数です。
一部の人々は言う:私はルーカスを拡大していきます!!(しかし、著者らはまたありません)- しかし、この質問には、任意の拡張子を使用する必要はありません\(ルーカスは\) 。
- 以降\(= 2 999 911 658 \ times3 \ times4679 \ times35617 \) 、即ち、各数の素因数の数である\(1 \) 。
- 我々は、単に必要であることを見つけるように、|(\ sum_ {N D \を C_ {n}は^ {D} \}) を持つ4つのモジュロ番号の後にこれらの結果、\(CRTが\) (マージされる(\ CRT \)これらの4つのリストの合同方程式の答えを見つけるを教えてくれる、あなたは金型を得ることができますが、\(M \)の意味でユニークなソリューション)。
- そして、素数の問題の弾性率が、直接使用に変身\(ルーカス\)定理はそれを修正します。
- \(ルーカス\)定理(\(P \)である素数):\ (\ Binom {N-} {M} = \ Binom {N- / P} {M / P} \ Binom {N - \%のP} {M \ P}%\) 。
#include <bits/stdc++.h>
//999911658=2*3*4679*35617
const int mod = 999911659;
const int p[5] = {0, 2, 3, 4679, 35617};
const int MaxN = 4e4 + 5;
int n, G;
int a[5], fac[MaxN], inv[MaxN];
inline void add(int &x, const int &y, const int &mod)
{
x += y;
x >= mod ? x -= mod : 0;
}
inline int qpow(int a, int b, const int &mod)
{
int res = 1;
for (; b; b >>= 1, a = 1LL * a * a % mod)
if (b & 1)
res = 1LL * res * a % mod;
return res;
}
inline int lucas(const int &n, const int &m, const int &mod)
{
if (n < m) return 0;
if (n < mod && m < mod) return 1LL * fac[n] * inv[m] % mod * inv[n - m] % mod;
return 1LL * lucas(n % mod, m % mod, mod) * lucas(n / mod, m / mod, mod) % mod;
}
inline int solve(const int &p)
{
fac[0] = 1;
for (int i = 1; i < p; ++i)
fac[i] = 1LL * fac[i - 1] * i % p;
inv[p - 1] = qpow(fac[p - 1], p - 2, p);
for (int i = p - 2; i >= 0; --i)
inv[i] = 1LL * inv[i + 1] * (i + 1) % p;
int res = 0;
for (int i = 1; i * i <= n; ++i)
if (n % i == 0)
{
add(res, lucas(n, i, p), p);
if (i * i != n)
add(res, lucas(n, n / i, p), p);
}
return res;
}
int main()
{
scanf("%d%d", &n, &G);
if (G == mod)
{
puts("0");
return 0;
}
for (int i = 1; i <= 4; ++i)
a[i] = solve(p[i]);
int lcm = mod - 1, ans = 0;
for (int i = 1; i <= 4; ++i)
{
int x = lcm / p[i];
add(ans, 1LL * x * qpow(x, p[i] - 2, p[i]) % lcm * a[i] % lcm, lcm);
}
printf("%d\n", qpow(G, ans, mod));
return 0;
}