除数
除数について
定義:
整数dによって整数nの剰余をn 0、すなわち、D割り切れる場合、番号について、DのNと呼ばれる、N Dの倍数である、Dで示され| N
算術の基本定理では\(N \) 、次のように分解することができます
\ [N = \ prod_ {i = 1} ^ m個のP_I ^ {C_I}、\ P_1 <P_2 <... <P_M、\ C_I∈N ^ * \]
その後、\(N \)数は約から正の数であります:
\ [(C_I + 1)*(C_I + 2)* ...(c_m + 1)= \ prod_ {i = 1} ^ {M}(C ^ I + 1)\]
\(N \)すべての正の約数のは、以下のとおりです。
\ [\ prod_ {i = 1} ^ {M} {(\ sum_ {J = 0} ^ {C ^ I}(P_I)^ J)} \]
ソリューション\(N \)は、いくつかの正について設定されています
- トライアル部門
$ \ $ Qquad番号場合\(X \)がある\(N \)次に、除数(N /d≤\ SQRT N \ \) も(N \)\の除数。
$ \ Qquad $除数は常にペアで来るので、そのスキャン\(X- = 1- \ sqrtのN \∈Z \) 、かどうかを試してください\(X- | N \) 。しかし、我々は、理由は完全な方形のために、特別な宣告完全な方形に持っている\(\ sqrtのN \∈Z \) 。
int factor[1600], num = 0;
for(int i = 1; i * i <= n; i++) {
if(n % i == 0) {
factor[++num] = i;
if(i != n/i)
factor[++num] = n / i;
}
}
$ \ $ Qquad要求\(1- \ SQRT N \)各セットのn個除数- COLORED
基本的な考え方:
トライアル部門とは異なり、我々はターン数でそれぞれを検討することができます\(X \) 、場所\(X \)除数がされている(X、2倍、3倍... \ \)を
vector<int> factor[SIZE];
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n / i; j++)
factor[i*j].push_back(i);
//输出
for(int i = 1; i <= n ;i++) {
for(int j = 0; j < factor[i].size; j++)
printf("%d ",factor[i][j]);
putchar('\n');
}
小さなデータで$ \ $ Qquad(\(n∈[4,16] \) )、トライアル分割多重方法よりも高速で、複雑\(O(N \のSQRTのN )\)
除数関連コンテンツ:
1.最大公約数| \(GCDの\)
- 定義:
自然数の場合は\(X \)を満たす| \(\ x)のおよび\(X- | B \) 、と呼ばれる\(X \)される(\)を\ている\(のb \) 、その後、公約数(\ MAX(X)\)されている\(\)と\(Bが\)最大公約数である、と呼ばれる\(GCD(B)\) 。
満たしながらあれば、同様に、(| X \)\と\(B | X \)を、次いで\(X \)がある\(\)と\(B \)ように、共通の複数(X \ \ )の最小値で\(B \)最小公倍数と呼ば\(LCM(B)\) 。
定理:
\ [∀a、b∈N、\ qquad \ qquad GCD(a、b)は* LCM(a、b)は、* Bが\を=]
自分を試すことができます上で定義した証拠読者、あなたはまた、「基準アルゴリズムコンテストステップアップガイド」をすることができます
- 解決方法
で素因数分解に我々はすでに解決述べた\(GCDの\) 1.技術2.ユークリッドアルゴリズムを下げます:アルゴリズムを。
「算術の九章は、」以下のとおりです。
\ [∀a、b∈N、a≥b、\クワッドGCD(A、B)= GCD(B、AB)= GCD(AB)\]
\ [∀a、b∈N、\クワッドGCD(2A、2B)= 2gcd(B)\]
それは私たちの後ろに最適化されたバイナリを伴う2つの定理、上記重要である(GCDの\)\
ユークリッドアルゴリズム:
\ [∀a、b∈N、≠0、B \ qquad GCD(A、B)= GCD(B、A \クワッドMOD \クワッドB)\]
これは、おなじみ与えユークリッドアルゴリズム:
//递归形式
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
//非递归形式
int gcd(int a, int b) {
int temp;
while(b) {
temp=a % b;
a = b;
b = temp;
}
return a;
}
$ \ Qquad \ qquad \(ユークリッドアルゴリズムの複雑です\) O(ログ(A + B))$。高精度演算、達成することは容易ではない剰余のためには、代わりに減少テクニックをお勧めします。
$ \ Qquad \ qquadの\(もちろん、\) $も最適化することができ、GCD(最適化は前述したバイナリです)。
- なぜ最適化することができますか?ユークリッドアルゴリズムモジュロ演算を使用するため、一定の低速大実行するように、+最適化されたバイナリ減少有するので\(GCD \)
\(A = 0、\クワッドリターン\クワッドB; \クワッド\ミッド\クワッドB = 0、\クワッドリターン\クワッド; \)
\(A <B、A \クワッドXOR = \クワッドB、\クワッドB \クワッドXOR = \クワッド、\クワッドA \クワッドXOR = \クワッドB; \) (一意のバイナリ交換)
\(A \) &\(1 \)且\(Bの\) &\(1 \)、$ \クワッドANS = 2gcd(>> 1、B >> 1); $
\(\) &\(1 \) !且\(B \) &(\ 1)\、$ \クワッドANS = GCD(>> 1、B); $
! \(\)& \(1 \)且\(のb \) &\(1 \)、$ \クワッドANS = GCD(A、B >> 1); $
! \(\)& \(1 \) !且\(B \) &\(1 \)、$ \クワッドANS = GCD( - B、B)$。
//下面代码返回gcd(a,b)的值同时把b赋予这个值,不需要可以把&去掉
int gcd(int a,int &b) {
if(a == 0 || b == 0) return b = a + b;
int n = 0, m = 0;
for(; !(a & 1); a >>= 1, n++);
for(; !(b & 1); b >>= 1, m++);
n = m < n ? m : n;
while(a) {
if(a < b) { a ^= b, b ^= a, a ^= b;}
if(!(a -= b)) return b <<= n;
while(!(a & 1)) a >>= 1;
}
}
負右しかしながら、上記のコードが間違って陰性である場合注意、\(1 \)ビットと他の\(2 \)と同じではない、上記負ではなく分割の通常の使用のビット操作を検出しました。
2.オイラーの主要機能
- 定義:
\(∀a、b∈N\) 、もし\(GCD(A、B)= 1 \)と呼ばれる、\(B \)プライム。
3つの数字や状況に上記類推するために、ここではそれらを繰り返さないで、読者が自分で関連情報にアクセスすることができます。
オイラー機能
$ \ $ Qquad \(1-N \)と\(N \)素数は、オイラー関数を呼び出しと呼ばれる\(Φ(N)\) 。
基本的な演算定理に、\(N = \ prod_ 1} = {I ^ M ^ {P_I} C_I \。) 、その後:
\ [φ(N)= N * \ FRAC {1-P_1} {P_1} * \ FRAC {1-P_2} {P_2} * \ FRAC {1-P_3} {P_3} * ... * \ FRAC {1- P_M } {P_M} = N * \ prod_ {素数\ P | N}(1- \ FRAC {1} {P})\]
オイラー関数の計算式は、我々は、オイラー関数を得るために、品質係数の唯一の分解が必要になります。
//参考代码(源于《算法竞赛进阶指南》)
int phi(int n) {
int ans = n;
for(int i = 2; i <= sqrt(n); i++)
if(n % i == 0) {
ans = ans / i * (i - 1);
while(n % i == 0) n /= i;
}
if(n > 1) ans = ans / n * (n - 1);
return ans;
}
- オイラー関数の性質:
\(∀n> 1,1-N \ ) と\(N- \)素数とされている(Φ(N)/ 2 \ N- *)\。
もし\(GCD(A、B)= 1 \) 、すなわち\(B \)プライム、次いで\(Φ(AB&)=Φは(A)、Φ(B)\) 。
セット\(P \)があれば、素数である\(P \ミッドN \)と\(P ^ 2 \ MID N- \) 、次いで\(Φ(N)= [ピー](N / P)* P \) 。
セット\(P \)場合、素数である\(P \ミッドN \)と\(NMID N- \ P ^ 2 \)次に、\(φ(N)=のφ (N / P)*(P-1) \) 。
\(\ sum_ {Dの\ミッドN}φ(D)= N \) 。
乗法機能:
$ \ Qquad $場合\(GCD(A、B)= 1 \) 、そこ\(F(AB)= F(A)fは(B)\) 、次に関数として知られている\(F \)乗法関数です。
- 場合\(F \)は関数の積で算術の基本定理である\(N = \ prod_ {私は= 1} ^ M P_I ^ {C_I} \) 、次いで$(N)F = \ prod_ {I = 1} ^ MF(P_I ^ { C_I})$。
(第6オイラー関数の性質を持ちます)
\(* \)完全に乗法関数です。
\ [∀a、b∈Z、\ qquadのF(AB)= F(A)は、f(B)\]
乗法関数に展開は、コンテンツが簡単な紹介以下、より難解で、非常に大きいです。
などの一般的な乗法機能
\(Φ(N) \) -オイラー関数
\(σ(N) \) -約数関数
\(μ(N) \) -メビウス関数
\(σ_0(N-) \) -関数のについてのいくつかの数
\(σ_k(N-) \) -番号と機能番号について
\(GCD(N、K) \) -最大公約数関数、(Kを\)\一定時間
\(1(N)= 1 \) -私はこれが何であるかを知りません
\(F(N)は、N-を\ =) -私はまだ何であるかわかりません
$ \ Qquadドルもう一つのポイントは、直線的に選別されている乗法関数であります
- ディリクレ畳み込み
まず、次の補完することにより開始数論関数定義を:
終域:任意に設定した値の範囲を含みます
算術関数:ドメインは、正の整数である、ドメインを伴う複雑な関数であります
さて、私たちは紹介して始めることができますディリクレ畳み込みのを。
定義\(fは、G \)数論的関数、そのディリクレ畳み込みは以下のように表すことができる\(F * G \) 、提供\(F * G = H \) 。
\ [H(N)= \和_ {D | N} F(D)G \ビッグ(\ FRAC {n}は{D} \ビッグ)\]
場合\(F、Gの\)が乗法関数であり、明らかに、\(H \)はまた、乗法関数です。
証明します
$ \ $配置さqquadの\(N = * Bが\ ) と\(B \)互いに素、すなわち\(GCD(A、B)= 1 \。) :
\ [H(N)= \和_ {D_1 |、D_2 | B} F(d_1d_2)G \ビッグ(\ FRAC {A} {D_1} \ FRAC {B} {D_2} \ビッグ)\]
\ [= \ sum_ {D_1 |、D_2 | B} F(D_1)F(D_2)G \ビッグ(\ FRAC {A} {D_1} \ビッグ)G \ビッグ(\ FRAC {B} {D_2} \ビッグ)\]
\ [= \ sum_ {D_1 | A} F(D_1)G \ビッグ(\ FRAC {A} {D_1} \ビッグ)\ sum_ {D_2 | B} F(D_2)G \ビッグ(\ FRAC {B} {D_2} \ビッグ)\]
\ [= hの(A)* H(B)\]
$ \ Qquad $証拠。
アルゴリズム
ディリクレ畳み込み演算を満たすために:
\(F * F * G = G \) (可換)
\((F * G)= F * H *(F * G)\) (結合則)
\(F *(G + H)+ = F * F * G H \) (分配性)
場合\(F、Gの\)は関数の積であり、\(F * Gが\)は乗法関数です。(ネイチャー)
ディリクレ畳み込み関連
以下は、あるいはオイラーの関数に戻ります。
我々が使用できる$ \ $ Qquad (エラトステネス\の)\ふるい、オイラー関数に従って計算される、\(O(NlogN)を\)解決内\(2-N \)オイラー数の各々に機能。
int phi[SIZE];
void eluer(int n) {
for(int i = 2; i <= n; i++) phi[i] = i;
for(int i = 2; i <= n; i++)
if(phi[i] == i)
for(int j = i; j <= n; j += i;)
phi[j] = phi[j] / i * (i - 1);
}
$ \ Qquad $それが乗法関数であるので、オイラーの線形関数にそれを最適化する方法を、次に、リニアふるいすることができますか?のは、素数のふるい線形思考を確認してみましょう(素数のふるい詳細)、リニアふるい、各合成数\(N \)その素因数が、一度ふるいになり、次のいくつかのプロパティを使用します。
定理3:みましょう\(P \)があれば、素数である\(P \半ばのn \\)と$ P ^ 2 \ MID N- \(、その後、\) [ファイ](N-)= [ファイ](N / P)* Pの$ 。
定理4:みましょう\(P \)があれば、素数である\(P \半ばのn \\) NMID N- \ P ^ 2と$ (\その後、)\ [ファイ](N-)= [ファイ](N / P)*(P -1)$
我々は、から、これら2つの複合数定理をスクリーニングに使用することができる(φ(N / P)\ )\ する再帰(\、φ(N))\します。
素数のふるい、リニアふるいについて書くの2種類がありますので、実際には、ほとんど同じですが、読者の便宜のために、ここで与えられます。
//法一 :
int v[SIZE], pri[SIZE], phi[SIZE], num;
void promoted_eluer(int n) {
for(int i = 2; i <= n; i++) {
if(v[i] == 0)
pri[++num] = i, phi[i] = i - 1;
for(int j = 1; j <= num && i * pri[j] <=n; j++) {
v[i * pri[j]] = 1;
phi[i * pri[j]]=
phi[i] * (i % pri[j] ? pri[j] - 1 : pri[j]);
if(i % pri[j] == 0) break;
}
}
}
//法二:
int v[SIZE], pri[SIZE], phi[SIZE], num;
void promoted_eluer(int n) {
for(int i = 2; i <= n; i++) {
if(v[i] == 0)
pri[++num] = i, phi[i] = i - 1, v[i] = i;
for(int j = 1; j <= num; j++) {
if(pri[j] > v[i] || pri[j] > n / i) break;
v[i * pri[j]] = pri[j];
phi[i * pri[j]]=
phi[i] * (i % pri[j] ? pri[j] - 1 : pri[j]);
}
}
}
章の練習の終わり※
\(終わり\)
\(PS:\)
順序と内容を説明するよりも、基準:李Yudong「アルゴリズムコンテストステップアップガイド」