競プロにおける数学(ほぼ数論)関連のメモ.
コンテスト中に確認できるように,細かい証明とかはせず,重要な部分だけ書く.
オイラーのΦ関数
概要
正整数性質
オイラーのΦ関数には以下のような性質がある.例題
問題2
座標と
座標がそれぞれ
以上
以下となるような座標平面上の格子点のうち,原点
と線分で結んだとき他の格子点を通らないようなものの数を求めよ.
制約
・
エラトステネスの篩
概要
アルゴリズムは以下の通り.
から
までの整数を用意する.
から昇順に
(実際は
でいい)を越えるまで3を繰り返す.
が消されてないなら,残っている整数のうち
より大きい
の倍数をすべて消す(実際は
以上の
の倍数でいい).
- 残った整数が素数.
計算量
このアルゴリズムの計算量は応用
このアルゴリズムの重要な点は,つまり,このアルゴリズムは
例題
問題1
のすべての整数
について,
の最大素因数を求めよ.
制約
・
解答
取得した素因数の中で最大のものを求めればよい.N = int(input()) ans = list(range(N+1)) for i in range(2,N+1): # 素数ならans[i]=iとなっている if ans[i] != i: continue for j in range(i*2,N+1,i): ans[j] = i print(ans[2:])
この問題は高速な素因数分解のために用いられたりもする.
問題2
のすべての整数
について,
の素因数の数(例えば
の素因数の数は
の
個)を求めよ.
制約
・解答
篩に掛けるたびにカウントすればよい.
N = int(input()) ans = [0]*(N+1) for i in range(2,N+1): if ans[i] != 0: continue for j in range(i,N+1,i): ans[j] += 1 print(ans[2:])
N = int(input()) ans = list(range(N+1)) for i in range(2,N+1): if ans[i] != i: continue for j in range(i,N+1,i): ans[j] = ans[j] // i * (i-1) print(ans[2:])
線形篩
概要
エラトステネスの篩では,各合成数について,その素因数の数だけ篩に掛けていた.各合成数について,その最小の素因数だけで篩に掛けることができればspf = [0] * (N+1) prime = [] for m in range(2,N+1): if spf[m] == 0: spf[m] = m prime.append(m) for p in prime: if p > spf[m] or p*m > N: break spf[p*m] = p
上で説明したエラトステネスの篩と同様に,このアルゴリズムは素数列挙のアルゴリズムではなく以下の自然数
に対して,
の最小の素因数を取得できるアルゴリズムであると捉えることができる.さらに,このアルゴリズムの嬉しい点は任意の
に対して,
を篩に掛けるときに
と表される
が(合成数ならば)既に篩に掛けられている点である.
以下の自然数
に対して,
が
や
や
から高速に計算できるなら,このアルゴリズムで高速に求めることができる.
乗法的関数
完全乗法的関数
任意の自然数に対して
が成り立つとき,
を完全乗法的関数という.
が完全乗法的関数ならば,
であるので
が合成数のとき,すでに計算された
から
が計算できる(
は
以下の素数なので
は計算されている).
が素数のときに
が高速に計算できさえすれば,
以下の自然数
に対する
の値が高速に計算できる.
例題
問題1
のすべての整数
について,「
と互いに素である
以下の自然数の個数」を求めよ.
制約
・
解答
spf = [0] * (N+1) phi = [0] * (N+1) prime = [] for m in range(2,N+1): if spf[m] == 0: spf[m] = m phi[m] = m-1 prime.append(m) for p in prime: if p > spf[m] or p*m > N: break spf[p*m] = p if m%p == 0: phi[p*m] = p*phi[m] else: phi[p*m] = (p-1)*phi[m] print(phi[2:])
メビウス関数
概要
メビウス関数性質
メビウス関数には以下のような性質がある.-
(
は互いに素)
-
-
-
例題
問題1
長さの数列
が与えられる.
かつ
となる
の数を求めよ.
制約
・
二項係数
概要
二項係数性質
二項係数には以下のような性質がある.自明な下位互換は書いてない.ただし,
例題
問題1
を求めよ.
解答
床関数/天井関数
実数実数
性質
-
-
-
-
-
-
-
-
(
)
-
(
は互いに素)
-
-
-
の値の種類は
個
-
となる整数
の範囲は
床関数の性質に性質3を適用することで天井関数の性質に変えることができる.
例題
問題1
を求めよ.
制約
・
解答
したがって
N = int(input()) ans = 0 L = 1 while L <= N: R = N // (N // L) ans += (R - L + 1) * (N // L) L = R + 1 print(ans)
問題2
を求めよ.
制約
・
・解答
性質6をとして用いると,
となる.(性質11を用いて
と変換した)
さらに性質6を用いると
となりで求められる.
N,M = map(int,input().split()) print((pow(10,N,M**2)-pow(10,N,M))//M)