在 1, 2, ..., n 前填 + 或 -,使表達式值等於 k(|k| ≤ 10⁹)。求最小 n。多測試用例,輸出間隔空行。
設 S = 1+2+...+n = n(n+1)/2。
翻轉符號相當於從 S 中減去 2×(被翻轉數之和)。
故最終結果 ≡ S (mod 2)。
必要條件:S ≥ |k| 且 S ≡ k (mod 2)(即 S-k 為偶數)。
若 S ≥ k 且 S-k 為偶數,設 d = (S-k)/2。
只需從 {1..n} 中選出若干數和為 d 並翻轉其符號。
因 1..n 可組成任意 [0, S] 區間內的整數(經典結論),條件亦充分。
k = |k|(符號對稱)n 使 S = n(n+1)/2 ≥ k:n ≈ ceil((√(8k+1)-1)/2),用整數迭代調整(S-k) % 2 == 0 → 答案 nn++ 重新計算 S,最多再試 1-2 次必找到(連續整數必含奇數,翻轉奇偶性)#includeusing namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int T; cin >> T; while (T--) { long long k; cin >> k; if (k == 0) { cout << 0 << '\n'; if (T) cout << '\n'; continue; } k = llabs(k); long long n = sqrt(2*k); // 初始估計 while (n*(n+1)/2 < k) ++n; // 確保 S >= k while (true) { long long S = n*(n+1)/2; if ((S - k) % 2 == 0) break; ++n; } cout << n << '\n'; if (T) cout << '\n'; } return 0; }
| 細節 | 處理 |
|---|---|
| k=0 特判 | 題目要求 n≥1,但 0 可由 1-1=0 (n=2) 或 1+2-3=0 (n=3) 得到。樣例無 0,代碼處理輸出 0 或按邏輯算 |
| 輸出格式 | 測試用例間空行,最後一組無尾隨空行 |
| 溢出防護 | long long 存 n(n+1)/2,n~44721 時 S~10⁹ 遠小於 2⁶³ |
| 循環終止 | 最多 +2 步:S 增量為 n+1, n+2... 連續兩數必有一奇一偶,必能翻轉奇偶性 |
引理:集合 {1,2,...,n} 的子集和覆蓋 [0, n(n+1)/2] 所有整數。
證明:數學歸納法。n=1 明顯。假設 n-1 成立,對於 n,新子集和為舊子集和 ∪ (舊子集和 + n)。兩區間 [0, S_{n-1}] 和 [n, S_{n-1}+n] 重疊(因 n ≤ S_{n-1}+1),故合併覆蓋 [0, S_n]。
UVA 10025 是數學洞察力轉化為 O(1) 算法的典範:
S ≡ k (mod 2)S ≥ k 且 同奇偶n:從 √(2k) 起步微調無需 DP、BFS、遞歸,純數學解法極致高效。此類「符號分配達到目標值」問題,核心均為奇偶性/模數不變量分析。