\(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 個數字要挑選
int num[4] = {};
int solutions = 0;
//
// pick() 每個位置挑選數字
// remain: 還剩多少可以分
// id: 哪一個位置在挑 0 ~ 3
//
void pick(int remain, int id)
{
}
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\) 的時候,剩下要湊的數字,剛好是某個整數的平方的話,這時候就有答案。
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_0\) 呢?就找最小的正整數 1
當代表囉!
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}\)
ubound = sqrt(remain/(4-id));
逾時了!!
原因:需要反覆計算某數的平方
解方:在程式一開始時預先將平方數建表,改用查表法
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;
}
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 |
or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?
Please give us some advice and help us improve HackMD.
Do you want to remove this version name and description?
Syncing