Tsuzu's Notes

主にIT系備忘録

フェルマー方程式/Fermat(JOI2007春合宿Day2 2nd)

春合宿まで精進するぞって言ってし始めたんですが結構始めから躓いていて早速数学に苦しめられています。(本選参加記はもう少ししたら書きます。)
Fermatも理解できず、LatteMaltaさん(@latte0119)に教えていただいてなんとか理解できたので忘れないうちに備忘録としてまとめます。(ありがとうございました!)

問題概要

解法

まずはpで割った余りがaとなるxnのxの数をcount[a]など配列に保存しておく必要があります。単純に計算するとO(NP)かかりますが繰り返し二乗法を用いるとO(PlogN)で済みます。(繰り返し二乗法については割愛します。)
xn≡a(mod p), yn≡b(mod p), zn≡c(mod p)となるa, b, c(0 <= a, b, c <= p-1)を置きます。
ここまで考察するとaとbはそれぞれP通りあり、count[a]*count[b]*count[(a+b)%P]を全て足し合わせる解法が浮かびます。
2007年と古い問題であり、制約が104と小さいため上記の方法で行うO(N2)解法が結構ありますが当時はそれでは間に合いません 。

頭の良い人ならすぐにわかるのかもしれませんが私にはわかりませんでした。以下のようなことをしていきます。
c=1の時のx, y, zの組み合わせの個数はc>1の時の解の個数と一致する仮定を立てます。(O(P2)のコードを適当に書きましょう。)
これを証明していきます。

cがtの時のx, y, zの組み合わせの個数をf(t)と置く。
c=1となるとき、xn+yn≡1(mod p)。 c>1となるzをtと置き、tnを式全体にかけると、(xt)n+(yt)n≡tn(mod p)となります。この式よりzがtとなるとき、少なくとも(xt, yt)の組み合わせが解となります。(x, yはz=1の時の解です。) ここで、t>1においてxt≢x(mod p)かつyt≢y(mod p)であるため、f(1)<=f(t)(t > 1)…(1)。

また、xn+yn≡zn(mod p)においてzとpは互いに素であるからzの逆元をdと置くと(xd)n+(yd)n≡1(mod p)であり、(xd,yd)が必ずc=1の解となる。
(x, y)はznの時の解であるため、先程と同様にf(t)<=f(1)(t > 1)…(2)。

(1)(2)よりf(t)=f(1)である。
よって、f(0)+f(1)*(0を除くcの種類の数)で求められる。
コードはAtCoderの提出を参照。

感想

むずい!数学むずすぎるよ!
こんなもん仮定立てて証明までするとかできる気がしないんで本番であったら間違いなく仮定だけしてそうっぽい!wって言って組み始めそう…
というわけで一応まとめてみました。結構急ぎでまとめたので改善点とか結構あると思います。コメントやTwitter等で教えていただけると幸いです。