Skip to content

Commit cdd17eb

Browse files
committed
Math: Algebra Difference and Product - 絶対差と積で数える整数対
1 parent b2b5ae0 commit cdd17eb

1 file changed

Lines changed: 357 additions & 0 deletions

File tree

Lines changed: 357 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "0805330f",
6+
"metadata": {},
7+
"source": [
8+
"# Difference and Product - 絶対差と積で数える整数対\n",
9+
"\n",
10+
"* **プラットフォーム**: HackerRank\n",
11+
"* **問題ID**: Difference and Product\n",
12+
"\n",
13+
"---\n",
14+
"\n",
15+
"## 目次\n",
16+
"\n",
17+
"* [概要](#overview)\n",
18+
"* [アルゴリズム要点 (TL;DR)](#tldr)\n",
19+
"* [図解](#figures)\n",
20+
"* [証明のスケッチ](#proof)\n",
21+
"* [計算量](#complexity)\n",
22+
"* [Python 実装](#impl)\n",
23+
"* [CPython 最適化ポイント](#cpython)\n",
24+
"* [エッジケースと検証](#edgecases)\n",
25+
"* [FAQ](#faq)\n",
26+
"\n",
27+
"---\n",
28+
"\n",
29+
"<h2 id=\"overview\">概要</h2>\n",
30+
"\n",
31+
"* **問題要約**: 整数 $d$ と $p$ が与えられる。$|x-y|=d$ かつ $xy=p$ を満たす**有序**整数対 $(x,y)$ の個数を求める。\n",
32+
"* **入出力仕様(簡潔)**:\n",
33+
"\n",
34+
" * 入力: $T$ テスト、各行に $d\\ p$\n",
35+
" * 出力: 各テストについて解の個数(整数)\n",
36+
"* **関数シグネチャ(HackerRank 準拠・必須)**: `solve(d: int, p: int) -> int`\n",
37+
"* **想定データ構造**: 単一の整数演算のみ(補助配列不要)\n",
38+
"* **代表例**:\n",
39+
"\n",
40+
" * $d=1,\\ p=2 \\Rightarrow 4$\n",
41+
" * $d=0,\\ p=4 \\Rightarrow 2$\n",
42+
" * $d=-1,\\ p=1 \\Rightarrow 0$\n",
43+
"\n",
44+
"---\n",
45+
"\n",
46+
"<h2 id=\"tldr\">アルゴリズム要点 (TL;DR)</h2>\n",
47+
"\n",
48+
"* 和差変数を導入する:$s=x+y,\\ t=x-y$。すると\n",
49+
" $$\n",
50+
" |t|=d \\quad\\text{かつ}\\quad xy=\\frac{s^2-t^2}{4}=p \\ \\Rightarrow\\ s^2=4p+d^2\n",
51+
" $$\n",
52+
"* $N=4p+d^2$ とおく。$N$ が**完全平方**でなければ解は $0$。\n",
53+
"* $q=\\sqrt{N}$(整数)とすると、$s\\in{\\pm q}$、$t\\in{d,-d}$。\n",
54+
"\n",
55+
" * $q>0$ なら $s$ は $2$ 通り、$q=0$ なら $1$ 通り。\n",
56+
" * $d>0$ なら $t$ は $2$ 通り、$d=0$ なら $1$ 通り。\n",
57+
"* よって個数は\n",
58+
" $$\n",
59+
" \\bigl(1 + \\mathbf{1}*{q>0}\\bigr)\\times \\bigl(1 + \\mathbf{1}*{d>0}\\bigr)\n",
60+
" $$\n",
61+
"* ただし $d<0$ は $|x-y|=d$ を満たせないため常に $0$。\n",
62+
"* **計算量**: 時間 $O(1)$、空間 $O(1)$(`math.isqrt` による完全平方判定)。\n",
63+
"\n",
64+
"式変形と「通り数の数え方」が腑に落ちるよう、ステップごとに具体化します。数式は KaTeX で再掲し、ミニ例も置きます。\n",
65+
"\n",
66+
"---\n",
67+
"\n",
68+
"## 補足解説:TL;DR の具体化\n",
69+
"\n",
70+
"### 1) なぜ和差変数にするのか\n",
71+
"\n",
72+
"元の条件は\n",
73+
"\n",
74+
"* 差の条件:$|x-y|=d$\n",
75+
"* 積の条件:$xy=p$\n",
76+
"\n",
77+
"これを\n",
78+
"$$\n",
79+
"s=x+y,\\quad t=x-y\n",
80+
"$$\n",
81+
"に置き換えると、$x$ と $y$ を $s,t$ から\n",
82+
"$$\n",
83+
"x=\\frac{s+t}{2},\\quad y=\\frac{s-t}{2}\n",
84+
"$$\n",
85+
"で一意に復元できます(順序付きなので $(s,t)$ が変われば一般に $(x,y)$ も変わる)。\n",
86+
"\n",
87+
"差の条件はただちに $|t|=d$、つまり $t\\in{d,-d}$ と書けます。\n",
88+
"\n",
89+
"積の条件は\n",
90+
"$$\n",
91+
"xy=\\frac{(x+y)^2-(x-y)^2}{4}=\\frac{s^2-t^2}{4}=p\n",
92+
"$$\n",
93+
"で、これを $s$ について解けば\n",
94+
"$$\n",
95+
"s^2=t^2+4p\n",
96+
"$$\n",
97+
"ここで $|t|=d$ を代入すると\n",
98+
"$$\n",
99+
"s^2=4p+d^2\n",
100+
"$$\n",
101+
"\n",
102+
"### 2) 「完全平方」でなければ即 0\n",
103+
"\n",
104+
"$$\n",
105+
"N = 4p+d^2\n",
106+
"$$\n",
107+
"と置くと、上の式は $s^2=N$。$s$ は整数なので、$N$ が**完全平方**でなければ整数 $s$ は存在せず、解は $0$ です。\n",
108+
"(補足:$N<0$ のときも当然 $s^2=N$ は不可能なので $0$。)\n",
109+
"\n",
110+
"### 3) $s$ と $t$ の候補数を掛け合わせるだけ\n",
111+
"\n",
112+
"$N$ が完全平方なら $q=\\sqrt{N}\\in\\mathbb{Z}$ が存在します。このとき\n",
113+
"$$\n",
114+
"s\\in{+q,-q},\\quad t\\in{d,-d}.\n",
115+
"$$\n",
116+
"\n",
117+
"* $q>0$ なら $s$ は ${+q,-q}$ の **2 通り**。\n",
118+
"* $q=0$ なら $s=0$ の **1 通り**($+0$ と $-0$ は同じ)。\n",
119+
"* $d>0$ なら $t$ は ${+d,-d}$ の **2 通り**。\n",
120+
"* $d=0$ なら $t=0$ の **1 通り**(絶対値が 0 のときは符号の分岐がありません)。\n",
121+
"\n",
122+
"よって通り数は\n",
123+
"$$\n",
124+
"\\bigl(1+\\mathbf{1}*{q>0}\\bigr)\\times\\bigl(1+\\mathbf{1}*{d>0}\\bigr),\n",
125+
"$$\n",
126+
"つまり\n",
127+
"\n",
128+
"* $q>0$ なら $s$ 側が $2$、$q=0$ なら $1$\n",
129+
"* $d>0$ なら $t$ 側が $2$、$d=0$ なら $1$\n",
130+
" を掛け合わせた個数になります。\n",
131+
"\n",
132+
"> 注:$d<0$ の入力は、そもそも $|x-y|=d$ を満たせないので **常に 0**。\n",
133+
"\n",
134+
"### 4) 偶奇(パリティ)の心配は要らない理由\n",
135+
"\n",
136+
"$x=\\dfrac{s+t}{2},,y=\\dfrac{s-t}{2}$ が整数になるには、$s$ と $t$ の偶奇が一致している必要があります。\n",
137+
"ここで $t=\\pm d$、$s^2=4p+d^2$ より\n",
138+
"$$\n",
139+
"s^2 \\equiv d^2 \\pmod{4}\n",
140+
"$$\n",
141+
"が成り立つので、$s$ と $d$ は同じ偶奇になります。よって $t=\\pm d$ とも偶奇一致し、$x,y$ は必ず整数になります。\n",
142+
"(完全平方を満たした時点で偶奇条件は自動で通ります。)\n",
143+
"\n",
144+
"---\n",
145+
"\n",
146+
"## ミニ例で確認\n",
147+
"\n",
148+
"### 例1:$d=1,\\ p=2$\n",
149+
"\n",
150+
"* $N=4p+d^2=8+1=9$ は完全平方、$q=3>0$。\n",
151+
"* $s\\in{+3,-3}$(2 通り)、$t\\in{+1,-1}$(2 通り)で合計 $2\\times 2=4$。\n",
152+
"* 復元してみると\n",
153+
" $$\n",
154+
" (s,t)=(3,1)\\Rightarrow (x,y)=\\Bigl(\\frac{3+1}{2},\\frac{3-1}{2}\\Bigr)=(2,1) \\\n",
155+
" (3,-1)\\Rightarrow (2,-1) \\\n",
156+
" (-3,1)\\Rightarrow (-1,-2) \\\n",
157+
" (-3,-1)\\Rightarrow (-2,-1)\n",
158+
" $$\n",
159+
" で確かに 4 通り。\n",
160+
"\n",
161+
"### 例2:$d=0,\\ p=4$\n",
162+
"\n",
163+
"* $N=4p+d^2=16$、$q=4>0$。\n",
164+
"* $s$ は 2 通り($\\pm 4$)、$t$ は 1 通り($0$)なので合計 $2\\times 1=2$。\n",
165+
"* 復元:$(s,t)=(4,0)\\Rightarrow (2,2)$、$(-4,0)\\Rightarrow (-2,-2)$。\n",
166+
"\n",
167+
"### 例3:$d=-1,\\ p=1$\n",
168+
"\n",
169+
"* $d<0$ は不可能なので即 $0$。\n",
170+
"\n",
171+
"---\n",
172+
"\n",
173+
"## つまずきポイント早見\n",
174+
"\n",
175+
"* **$q=0$ を 2 通りと数えない**:$s=\\pm 0$ は同一。\n",
176+
"* **$d=0$ を 2 通りと数えない**:$t=\\pm 0$ は同一。\n",
177+
"* **完全平方チェックだけで十分**:満たせば偶奇も自動で揃う。\n",
178+
"* **順序対であることに注意**:$t$ の符号違いで $(x,y)$ の順序が入れ替わるため、$d>0$ なら $t$ 側で 2 通りが立つ。\n",
179+
"\n",
180+
"これで、TL;DR の各 bullet が「なぜそう数えるか」までクリアになるはずです。\n",
181+
"\n",
182+
"---\n",
183+
"\n",
184+
"<h2 id=\"figures\">図解</h2>\n",
185+
"\n",
186+
"**フローチャート(式変形の流れ)**\n",
187+
"\n",
188+
"```mermaid\n",
189+
"flowchart TD\n",
190+
" Start[開始]\n",
191+
" Eq1[\"和差の導入 s=x+y, t=x-y\"]\n",
192+
" Transform[\"積の式変形で s^2=4p+d^2\"]\n",
193+
" CheckSquare[N が完全平方か判定]\n",
194+
" Count[s,t の通り数を積]\n",
195+
" Output[個数を出力]\n",
196+
"\n",
197+
" Start --> Eq1\n",
198+
" Eq1 --> Transform\n",
199+
" Transform --> CheckSquare\n",
200+
" CheckSquare --> Count\n",
201+
" Count --> Output\n",
202+
"```\n",
203+
"\n",
204+
"*説明*: 和差変数で二次式に落としてから、完全平方かどうかのみを判定し、$s$ と $t$ の選択肢の積で個数を得る。\n",
205+
"\n",
206+
"**データフロー(入力から結果まで)**\n",
207+
"\n",
208+
"```mermaid\n",
209+
"graph LR\n",
210+
" A[\"入力 d,p\"]\n",
211+
" B[\"N=4p+d^2\"]\n",
212+
" C[\"q=isqrt(N)\"]\n",
213+
" D[完全平方チェック]\n",
214+
" E[個数計算]\n",
215+
" F[出力]\n",
216+
"\n",
217+
" A --> B\n",
218+
" B --> C\n",
219+
" C --> D\n",
220+
" D --> E\n",
221+
" E --> F\n",
222+
"```\n",
223+
"\n",
224+
"*説明*: $N$ の計算と整数平方根での完全平方判定を経て、通り数の直積で答えを得る。\n",
225+
"\n",
226+
"---\n",
227+
"\n",
228+
"<h2 id=\"proof\">証明のスケッチ</h2>\n",
229+
"\n",
230+
"* **設定**: $s=x+y,\\ t=x-y$ とする。$|t|=d$ より $t\\in{d,-d}$。\n",
231+
"* **主要式**: $xy=\\dfrac{s^2-t^2}{4}=p$ より $s^2=4p+d^2$。\n",
232+
"* **必要十分性**:\n",
233+
"\n",
234+
" * $N=4p+d^2$ が完全平方であれば $q=\\sqrt{N}\\in\\mathbb{Z}$ が存在し、$s\\in{\\pm q}$ を取れる。\n",
235+
" * $t\\in{d,-d}$ と組にすれば\n",
236+
" $$\n",
237+
" x=\\frac{s+t}{2},\\quad y=\\frac{s-t}{2}\n",
238+
" $$\n",
239+
" は整数となる($s^2\\equiv d^2 \\pmod{4}$ が成り立ち、$s$ と $d$ の偶奇が一致するため)。\n",
240+
" * 逆に $N$ が完全平方でなければ整数 $s$ は存在せず、よって解は存在しない。\n",
241+
"* **計数**:\n",
242+
"\n",
243+
" * $q>0$ のとき $s$ は $2$ 通り、$q=0$ のとき $1$ 通り。\n",
244+
" * $d>0$ のとき $t$ は $2$ 通り、$d=0$ のとき $1$ 通り。\n",
245+
" * よって個数は $\\left(1+\\mathbf{1}*{q>0}\\right)\\left(1+\\mathbf{1}*{d>0}\\right)$。\n",
246+
"* **基底ケース**:\n",
247+
"\n",
248+
" * $d<0$ は $|x-y|=d$ が不可能なので $0$。\n",
249+
" * $d=0,\\ p=0$ では $N=0$、$q=0$、$s=0,\\ t=0$ の一組 $(0,0)$ のみで $1$。\n",
250+
"* **終了性**: 各判定は有限個の整数演算のみで完了する。\n",
251+
"\n",
252+
"---\n",
253+
"\n",
254+
"<h2 id=\"complexity\">計算量</h2>\n",
255+
"\n",
256+
"* **時間計算量**: $O(1)$\n",
257+
"* **空間計算量**: $O(1)$\n",
258+
"\n",
259+
"---\n",
260+
"\n",
261+
"<h2 id=\"impl\">Python 実装</h2>\n",
262+
"\n",
263+
"> 注: HackerRank では関数ベースで採点されます。下記は **CPython 3.13.3** 想定、型注釈付き、純粋関数です。スタブ(入出力処理)はプラットフォーム側に従ってください。\n",
264+
"\n",
265+
"```python\n",
266+
"from __future__ import annotations\n",
267+
"from typing import Final\n",
268+
"import math\n",
269+
"\n",
270+
"def solve(d: int, p: int) -> int:\n",
271+
" \"\"\"\n",
272+
" |x - y| = d かつ x*y = p を満たす有序整数対 (x,y) の個数を返す。\n",
273+
"\n",
274+
" 数式対応(本文の KaTeX と対応):\n",
275+
" - s = x + y, t = x - y\n",
276+
" - |t| = d\n",
277+
" - x*y = (s^2 - t^2)/4 = p より s^2 = 4p + d^2\n",
278+
" - N = 4p + d^2\n",
279+
" - N が完全平方で q = sqrt(N) が整数なら:\n",
280+
" s は {+q, -q}(q>0 で2通り、q=0で1通り)\n",
281+
" t は {+d, -d}(d>0で2通り、d=0で1通り)\n",
282+
" 個数 = (1 if q==0 else 2) * (1 if d==0 else 2)\n",
283+
" - d < 0 のときは |x - y| = d を満たせないので 0\n",
284+
" \"\"\"\n",
285+
" # |x - y| = d は d >= 0 が必須\n",
286+
" if d < 0:\n",
287+
" return 0\n",
288+
"\n",
289+
" # N = 4p + d^2\n",
290+
" N: Final[int] = 4 * p + d * d\n",
291+
" if N < 0:\n",
292+
" # 4p が負で d^2 を足しても負になる極端なケース(p が十分に負)\n",
293+
" return 0\n",
294+
"\n",
295+
" # 完全平方判定: math.isqrt は丸め誤差なしの整数平方根\n",
296+
" q: int = math.isqrt(N)\n",
297+
" if q * q != N:\n",
298+
" return 0\n",
299+
"\n",
300+
" s_count: int = 1 if q == 0 else 2\n",
301+
" t_count: int = 1 if d == 0 else 2\n",
302+
" return s_count * t_count\n",
303+
"```\n",
304+
"\n",
305+
"---\n",
306+
"\n",
307+
"<h2 id=\"cpython\">CPython 最適化ポイント</h2>\n",
308+
"\n",
309+
"* **`math.isqrt`**: 整数の平方根を誤差なく返し、完全平方判定に最適。\n",
310+
"* **任意精度整数**: Python の `int` は任意精度でオーバーフローを気にしない。\n",
311+
"* **分岐の最小化**: 判定順序を $d<0 \\Rightarrow N<0 \\Rightarrow$ 完全平方 の順にして早期リターン。\n",
312+
"\n",
313+
"---\n",
314+
"\n",
315+
"<h2 id=\"edgecases\">エッジケースと検証</h2>\n",
316+
"\n",
317+
"* $d<0$ $\\Rightarrow$ $0$。\n",
318+
"* $N=4p+d^2<0$(大きく負の $p$)$\\Rightarrow$ $0$。\n",
319+
"* $N$ が完全平方でない $\\Rightarrow$ $0$。\n",
320+
"* $d=0$:\n",
321+
"\n",
322+
" * $N=4p$ が完全平方なら $q=2\\sqrt{|p|}$ が整数のとき $s$ は $2$ 通り(ただし $q=0$ なら $1$ 通り)、$t$ は $1$ 通り。\n",
323+
" * 例: $d=0,\\ p=4 \\Rightarrow N=16,\\ q=4 \\Rightarrow 2$。\n",
324+
"* $d=0,\\ p=0$:\n",
325+
"\n",
326+
" * $N=0,\\ q=0 \\Rightarrow 1$($(0,0)$ のみ)。\n",
327+
"* 代表例との整合:\n",
328+
"\n",
329+
" * $d=1,\\ p=2$: $N=9,\\ q=3>0 \\Rightarrow (2)\\times(2)=4$。\n",
330+
" * $d=0,\\ p=4$: $N=16,\\ q=4>0 \\Rightarrow (2)\\times(1)=2$。\n",
331+
" * $d=-1,\\ p=1$: $d<0 \\Rightarrow 0$。\n",
332+
"\n",
333+
"---\n",
334+
"\n",
335+
"<h2 id=\"faq\">FAQ</h2>\n",
336+
"\n",
337+
"* **偶奇条件は確認不要か**\n",
338+
" $s^2=4p+d^2$ より $s^2 \\equiv d^2 \\pmod{4}$。$s$ と $d$ の偶奇が一致するため、$x=(s+t)/2,\\ y=(s-t)/2$ は常に整数になる。\n",
339+
"* **符号付きの $s$ を数える理由**\n",
340+
" $s=\\pm q$ はそれぞれ異なる $(x,y)$ を与える可能性があり、有序対の計数では両方を数える必要がある。\n",
341+
"* **なぜ $O(1)$ か**\n",
342+
" 各テストに対して加減乗算と `isqrt`、数回の比較のみで、入力値の大きさに関わらず定数時間で終わるため。\n",
343+
"\n",
344+
"---\n",
345+
"\n",
346+
"**補足(Mermaid と日本語フォント)**: Mermaid 図で日本語が豆腐になる場合、利用側の CSS で `.mermaid { font-family: \"Noto Sans JP\", sans-serif; }` のように指定してください。\n"
347+
]
348+
}
349+
],
350+
"metadata": {
351+
"language_info": {
352+
"name": "python"
353+
}
354+
},
355+
"nbformat": 4,
356+
"nbformat_minor": 5
357+
}

0 commit comments

Comments
 (0)