<style> img[alt ~= "bdr"] { border: 1px solid lightgrey; padding: 5pt} img[alt ~= "mh"] {max-height: 64%} div.flex {display: flex; justify-content: space-between;} div.flex.block { justify-content: center; align-items: center; color: #29292b; text-shadow: 0 0 3px #eee; background-color: rgba(255, 255, 0, 0.2); } .flex>p {margin: 0} .flex img:only-child {margin: 0} .flex.nmw img {max-width: none; max-height: none} div.big {font-size: 100pt} .center {text-align: center} .reveal section img {border: 1px solid #eee; background-color: transparent} .relative {position: relative} .absolute {position: absolute} .border {border: 3px solid red} .box {border: 3px solid red; position: absolute} table.celled td {border: 1px solid lightgrey;} table.celled tbody tr:last-child td {border-bottom: 1px solid lightgrey;} .reveal .slides { text-align: justify; } table#posinfo td { width: 170px; height: 170px; position: relative; text-align: center; } table#posinfo td span { position: absolute; left: 3pt; top: 3pt; font-size: 12pt; } </style> # a118: 03-4-指數2^k的四個自然數平方和之所有表示法 --- ![](https://i.imgur.com/dANMasB.png) ---- <div class="flex"> ![](https://i.imgur.com/4G1o0PG.png) ![](https://i.imgur.com/D13yNj6.png) </div> ---- ![](https://i.imgur.com/UCp1ho5.png) --- $2^{k} = n_0^2 + n_1^2 + n_2^2 + n_3^2$ 且 $n_0 \leq n_1 \leq n_2 \leq n_3$ 有 $n_0$ ~ $n_3$ 總共 4 個數字要挑選 ---- ``` cpp int num[4] = {}; int solutions = 0; // // pick() 每個位置挑選數字 // remain: 還剩多少可以分 // id: 哪一個位置在挑 0 ~ 3 // void pick(int remain, int id) { } ``` --- - 遞迴終止條件:已經在挑 $n_3$ 了,不需要再往下遞迴 - 檢查是否有解 - $n_0$ ~ $n_2$: $n_i$ 由前一個位置的數字($n_{i-1}$)開始,一直挑到這個位置的上限 - 依順序挑選一個數字 - 然後叫下一個位置起來挑 ---- ``` cpp void pick(int remain, int id) { if (id == 3) { // 終止條件 // 檢查是否有解,若有,印出一組答案 // ... 略 ... return; } int ubound; // 此位置挑數字的上限 int lbound; // 此位置挑數字的下限 // ...計算 lbound, ubound ... // ... // 開始挑數字 for (int n = lbound; i <= ubound; n++) { num[id] = n; pick(remain - n*n, id+1); } } ``` --- ## 何時有解? $n_3$ 不用挑,前面挑剩的全都給它。輪到 $n_3$ 的時候,剩下要湊的數字,剛好是某個整數的平方的話,這時候就有答案。 ``` cpp if (id == 3) { // 換 n3 挑數字 int r = sqrt(remain); if (r*r == remain) { // 有解 // ... } return ; } ``` --- ## 每個位置挑數字的下限 $n_0 \leq n_1 \leq n_2 \leq n_3$ 所以 - $n_1$ 的下限就是 $n_0$,從 $n_0$ 目前挑中的數字開始往後挑 - $n_2$ 的下限就是 $n_1$,從 $n_1$ 目前挑中的數字開始往後挑 ---- 等等,那 $n_0$ 呢?就找最小的正整數 `1` 當代表囉! ---- ```cpp if (id > 0) lbound = num[id-1]; else lbound = 1; ``` --- ## 每個位置挑數字的上限 對 $n_0$ 來說: $2^k = remain_0 = n_0^2 + n_1^2 + n_2^2 + n_3^2 \geq n_0^2 + n_0^2 + n_0^2 + n_0^2 = 4n_0^2$ => $n_0^2 \leq {remain_0 \over 4}$ => $n_0 \leq \sqrt{remain_0 \over 4}$ ---- $remain_0 - n_0^2 = remain_1 = n_1^2 + n_2^2 + n_3^2$ $n_0$ 挑了一個數字,輪 $n_1$ 挑選的時候,還剩 $remain_1$,此時還有 3 個數字還沒挑,$n_1$的最大值會發生在 $n_1 = n_2 = n_3$ 的時候 $remain_1 = n_1^2 + n_2^2 + n_3^2 \geq n_1^2 + n_1^2 + n_1^2 = 3n_1^2$ => $n_1^2 \leq {remain_1 \over 3}$ => $n_1 \leq \sqrt{remain_1 \over 3}$ ---- $remain_0 - n_0^2 - n_1^2 = remain_2 = n_2^2 + n_3^2 \geq n_2^2 + n_2^2 = 2n_2^2$ 同理 $n_2 = \sqrt{remain_2 \over 2}$ ---- ```cpp ubound = sqrt(remain/(4-id)); ``` --- ## 加速 逾時了!! ![](https://i.imgur.com/mCmVy08.png) ---- 原因:需要反覆計算某數的平方 ![](https://i.imgur.com/WGrqWQd.png) ![](https://i.imgur.com/SYpGIum.png) ---- 解方:在程式一開始時預先將平方數建表,改用查表法 ---- ``` cpp int sq[65536] = {}, solutions = 0; int main() { for (int i = 1; i < 65536; i++) sq[i] = i*i; int k; cin >> k; solutions = 0; solve(1 << k, 0); if (solutions == 0) cout << solutions << '\n'; return 0; } ``` ---- ``` cpp void solve(int remain, int id) { if (id == 3) { int n = sqrt(remain); if (sq[n] == remain) { // 印答案 } return; } // 計算 lbound, ubound ... // ... for (int n = lbound; n <= ubound; n++) { num[id] = n; solve(remain - sq[n], id+1); } } ``` --- ## 神奇的巧合 試著執行看看,好像有規律 ... |k||k|| |-|-|-|-| |1|0|7|0| |2|1 1 1 1|8|8 8 8 8| |3|0|9|0| |4|2 2 2 2|10|16 16 16 16| |5|0|11|0| |6|4 4 4 4|12|32 32 32 32|
{"metaMigratedAt":"2023-06-15T08:41:22.319Z","metaMigratedFrom":"YAML","title":"a118: 03-4-指數2^k的四個自然數平方和之所有表示法","breaks":true,"slideOptions":"{\"transition\":\"slide\",\"parallaxBackgroundImage\":\"https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg\"}","contributors":"[{\"id\":\"c9692e2a-34a5-463e-a7f8-b2fc30d8d8bd\",\"add\":4540,\"del\":123}]"}
    1871 views
   owned this note