問題
$\mathbb{F}_p$ 上の多項式 $f(x)$ について、Yun の SFD でスクエアフリー因子を求め、$g_1$ について次数 $d$ の既約因子の数を Cantor-Zassenhaus 流に数える。
制約
$2 \le p \le 10^9+7$ (素数)
$1 \le d \le n \le 200$
入出力例
入力例 1
7 1
4
1 0 0 0 1
出力例 1
Square-free factors:
g1 = x^4 + 1
No repeated factors.
Irreducible factors of degree 1: 2
ヒント (段階的開示)
ヒント1: 方向性
有限体上の多項式演算(加減乗除・GCD・微分・モニック化)を実装。スクエアフリー分解は $\gcd(f, f')$。
ヒント2: アプローチ
Yun: $g = \gcd(f, f')$, $f_1 = f/g$, $h = f'/g$。反復で各重複度の因子を抽出。
ヒント3: 誘導
DDF: 次数 $d$ の既約因子の積 = $\gcd(g_1, x^{p^d} - x)$。
poly_powmod で $x^{p^d} \bmod g_1$ を計算。模範解答 (Python)
import sys
input = sys.stdin.readline
def main():
p, target_deg = map(int, input().split())
n = int(input())
coeffs = list(map(int, input().split()))
MOD = p
def normalize(f):
while len(f) > 1 and f[-1] == 0:
f.pop()
return f
def poly_sub(f, g):
size = max(len(f), len(g))
res = [0] * size
for i, c in enumerate(f): res[i] = (res[i] + c) % MOD
for i, c in enumerate(g): res[i] = (res[i] - c) % MOD
return normalize(res)
def poly_mul(f, g):
if not f or not g: return [0]
res = [0] * (len(f) + len(g) - 1)
for i, cf in enumerate(f):
for j, cg in enumerate(g):
res[i+j] = (res[i+j] + cf*cg) % MOD
return normalize(res)
def poly_mod(f, g):
f = list(f)
g_lead_inv = pow(g[-1], MOD - 2, MOD)
while len(f) >= len(g):
while f and f[-1] == 0: f.pop()
if len(f) < len(g): break
coef = f[-1] * g_lead_inv % MOD
d = len(f) - len(g)
for i in range(len(g)):
f[d+i] = (f[d+i] - coef * g[i]) % MOD
while f and f[-1] == 0: f.pop()
return f if f else [0]
def make_monic(f):
if not f or all(c == 0 for c in f): return [0]
inv = pow(f[-1], MOD - 2, MOD)
return [c * inv % MOD for c in f]
def poly_gcd(f, g):
f, g = list(f), list(g)
while any(c != 0 for c in g):
f, g = g, poly_mod(f, g)
return make_monic(f)
def poly_div(f, g):
f = list(f)
g_lead_inv = pow(g[-1], MOD - 2, MOD)
result = []
while len(f) >= len(g):
while f and f[-1] == 0: f.pop()
if len(f) < len(g): break
coef = f[-1] * g_lead_inv % MOD
result.append((len(f) - len(g), coef))
for i in range(len(g)):
f[len(f) - len(g) + i] = (f[len(f) - len(g) + i] - coef * g[i]) % MOD
while f and f[-1] == 0: f.pop()
if not result: return [0]
max_deg = max(d for d, _ in result)
res = [0] * (max_deg + 1)
for d, c in result: res[d] = c
return normalize(res)
def derivative(f):
if len(f) <= 1: return [0]
return normalize([(i * f[i]) % MOD for i in range(1, len(f))])
def is_one(f):
return normalize(list(f)) == [1]
f = normalize(list(coeffs))
df = derivative(f)
sqfree_factors = {}
if all(c == 0 for c in df):
print("Square-free factors:")
print("(Characteristic issue)")
return
g = poly_gcd(f, df)
f_div = poly_div(f, g)
h = poly_div(df, g)
i = 1
while not is_one(f_div):
dfdiv = derivative(f_div)
diff = poly_sub(h, dfdiv)
gi = poly_gcd(f_div, diff)
factor = poly_div(f_div, gi)
if not is_one(factor):
sqfree_factors[i] = factor
f_div = gi
h = poly_div(diff, gi)
i += 1
def poly_to_str(P):
P = normalize(list(P))
if all(c == 0 for c in P): return "0"
terms = []
for deg in range(len(P) - 1, -1, -1):
c = P[deg]
if c == 0: continue
if deg == 0: terms.append(str(c))
elif deg == 1: terms.append("x" if c == 1 else f"{c}x")
else: terms.append(f"x^{deg}" if c == 1 else f"{c}x^{deg}")
return " + ".join(terms) if terms else "0"
print("Square-free factors:")
if 1 in sqfree_factors:
print(f"g1 = {poly_to_str(sqfree_factors[1])}")
else:
print(f"g1 = {poly_to_str(make_monic(f))}")
if all(k == 1 for k in sqfree_factors):
print("No repeated factors.")
else:
for k, v in sorted(sqfree_factors.items()):
if k > 1:
print(f"g{k} = {poly_to_str(v)} (multiplicity {k})")
g1 = sqfree_factors.get(1, make_monic(f))
def poly_powmod(base, exp, mod_poly):
result = [1]
base = poly_mod(base, mod_poly)
while exp > 0:
if exp % 2 == 1:
result = poly_mod(poly_mul(result, base), mod_poly)
base = poly_mod(poly_mul(base, base), mod_poly)
exp //= 2
return result
xpd = poly_powmod([0, 1], pow(p, target_deg), g1)
xpd_minus_x = poly_sub(xpd, [0, 1])
h_factor = poly_gcd(g1, xpd_minus_x)
deg_h = len(normalize(h_factor)) - 1
count = deg_h // target_deg
print(f"Irreducible factors of degree {target_deg}: {count}")
main()
Step-by-Step 解説
1有限体多項式演算
係数を $\bmod p$。除算はフェルマー逆元 $a^{p-2}$。
係数を $\bmod p$。除算はフェルマー逆元 $a^{p-2}$。
2Yun SFD
$\gcd(f, f')$ に重複度 $\ge 2$ の因子が入る。$h - f_1'$ の差分で各指数を分離。
$\gcd(f, f')$ に重複度 $\ge 2$ の因子が入る。$h - f_1'$ の差分で各指数を分離。
3DDF
$\mathbb{F}_{p^d}$ の元は $x^{p^d} - x$ の根。次数 $d$ 因子の積 = $\gcd(f, x^{p^d} - x)$。
$\mathbb{F}_{p^d}$ の元は $x^{p^d} - x$ の根。次数 $d$ 因子の積 = $\gcd(f, x^{p^d} - x)$。
4計算量
SFD $O(n^3)$、
SFD $O(n^3)$、
poly_powmod $O(n^2 d \log p)$。よくあるミス
| ミス | 原因 | 正しい書き方 |
|---|---|---|
| 負の係数の mod 忘れ | Python では正だが混乱 | (a - b) % MOD を徹底 |
| ゼロ多項式のGCD | f[-1] 不在 | normalize で先頭ゼロ除去 |
| モニック化忘れ | GCD の一意性破れる | 必ず leading 1 に |
次のステップ
- Equal-Degree Splitting で各既約因子を確率的に分割
- 楕円曲線の位数計算(BSGS + 多項式演算)