Tenka1 Programmer Contest 2019 E Polynomial Divisors
面白かったので。
解けてもおかしくなかった。めっちゃ苦戦したけど。
問題はこれ
E - Polynomial Divisors。
ポイントはフェルマーの小定理と、 次方程式の根の個数。
解説の準備
次方程式の根は高々 個以下
整域ならよい。つまり、普通に思いつくものはだいたいよい。
解説
を素数とする。
とする。
ただし、 とする。
のとき
任意の に対して、%p = 0] であればよい。
というのも、 次方程式は、 内に高々 個しか根を持たないが、
の元の個数は、 個なので、
は、恒等的に でなければならない。
今回は、 が でないことを使って、その約数を見ることにする。
のとき
上の場合の条件でも、もちろん成立する。
今からの議論はその場合も含む。
まず、
が を因子に持たないといけないので、
でなければならない。
というわけで、 の場合のみを考えれば良い。
つまり、残りの で でない整数 だけ調べれば良い。
フェルマーの小定理を思い出す。
すると、 になるので、
は次のように言い換えて良い。
各 ( の倍数でない整数 )に対して、
となる。
これは、 次方程式なので、根を高々 個しか持たない。
が を根に持たなければならない。
は除外して考えているので、
まとめると、
は根を少なくとも 個持たなければならない。
そういうものは、恒等的に であるようなものしか存在しない。
というのも、根の数を見れば、矛盾が見える。
ちなみに、
が でなければ の素因数だけを見ればよいが、
めんどくさいので、 以下の素数全てを調べている。
解答
def factors(z): ret = [] for i in range(2, int(z**(1/2))+1): if z%i == 0: ret.append(i) while z%i == 0: z //= i if z != 1: ret.append(z) return ret def eratosththenes(N): if N == 0: return [0] work = [True] * (N+1) work[0] = False work[1] = False for i in range(N+1): if work[i]: for j in range(2* i, N+1, i): work[j] = False return work N = int( input()) A = [ int( input()) for _ in range(N+1)] E = eratosththenes(N) Primes = [ i for i in range(N+1) if E[i] == 1] ANS = [] F = factors( abs(A[0])) for f in F: if f >= N+1: Primes.append(f) for p in Primes: if p >= N+1: check = 1 for i in range(N+1): # f が恒等的に 0 であるかどうかのチェック if A[i]%p != 0: check = 0 break if check == 1: ANS.append(p) else: poly = [0]*(p-1) for i in range(N+1): # フェルマーの小定理 poly[(N-i)%(p-1)] = (poly[(N-i)%(p-1)] + A[i])%p check = 0 if sum(poly) == 0 and A[N]%p == 0: # a_0 が 0 かつ、g が恒等的に 0 であることをチェックしている check = 1 if check == 1: ANS.append(p) for ans in ANS: print(ans)