Ural 1073「Square Country」:給定 N (≤ 60000),求表示為最少幾個完全平方數之和(如 344 = 18² + 6² + 2²,答案 3)。本文解析完全背包 DP 解法,並提及四平方和定理優化。
i² (i=1..244),因 245²=60025 > 60000。dp[j] = 湊成和 j 所需最少平方數個數 dp[0] = 0 dp[j] = min(dp[j], dp[j - i²] + 1) for all i² ≤ j
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 60000;
const int INF = 0x3f3f3f3f;
int dp[MAXN + 1];
int main() {
// 預計算所有答案
fill(dp, dp + MAXN + 1, INF);
dp[0] = 0;
for (int i = 1; i * i <= MAXN; ++i) {
int sq = i * i;
for (int j = sq; j <= MAXN; ++j) {
dp[j] = min(dp[j], dp[j - sq] + 1);
}
}
int n;
while (scanf("%d", &n) == 1) {
printf("%d\n", dp[n]);
}
return 0;
}
拉格朗日四平方和定理:任何自然數可表示為 ≤4 個平方數之和。結合勒讓德三平方定理可 O(1) 判斷答案:
int minSquares(int n) {
// 1. 完全平方數
int r = sqrt(n);
if (r * r == n) return 1;
// 2. 檢查 4^a(8b+7)
int m = n;
while (m % 4 == 0) m /= 4;
if (m % 8 == 7) return 4;
// 3. 兩個平方數之和
for (int i = 1; i * i <= n; ++i) {
int j2 = n - i * i;
int j = sqrt(j2);
if (j * j == j2) return 2;
}
return 3;
}
| 方法 | 預處理 | 單次查詢 | 適用場景 |
|---|---|---|---|
| 完全背包 DP | O(N√N) ≈ 1.5×10⁷ | O(1) | 多次查詢、N≤60000 |
| 數學定理判斷 | O(1) | O(√N) | 單次查詢、N極大(10¹⁸) |
本題是完全背包的標準應用。N=60000 時 DP 預計算極快(~0.03s),代碼簡單通用。若 N 更大或單次查詢,四平方和定理提供 O(√N) 甚至 O(1) 解法。面試中建議先給出 DP 通解,再展開數學優化作為進階討論。