b003 - 運算式 + - 符號設定問題
題目描述
題目要求找到最小的 n 值,使得 ± 1 ± 2 ± 3 ± ... ± n = k 成立。其中,每個數字前可以選擇加號或減號,目標是找到滿足等式的最小 n。
解題思路
核心思想是利用二分搜尋法來尋找可能的 n 值。首先,計算從 1 到 n 的和,即 n * (n + 1) / 2。然後,檢查是否存在一種符號組合,使得這個和等於目標值 k。
由於符號可以任意選擇,因此和的範圍是 [-n * (n + 1) / 2, n * (n + 1) / 2]。如果 k 超出這個範圍,則不存在解。
如果 k 在範圍內,則可以通過調整 n 的值,並檢查是否存在滿足條件的符號組合。程式碼中,bs 函數使用二分搜尋來找到一個可能的 n 值,使得 n * (n + 1) / 2 接近 k。
找到可能的 n 值後,程式碼會迭代增加 n,直到找到一個 n 值,使得 (n * (n + 1) / 2 - k) 是偶數。這是因為如果 n * (n + 1) / 2 - k 是偶數,則可以通過調整最後一個數字的符號來使等式成立。
複雜度分析
- 時間複雜度: O(log(a)),其中 a 是輸入的 k 值。二分搜尋的複雜度為 O(log(a)),而後面的 while 迴圈最多執行常數次。
- 空間複雜度: O(1),程式碼只使用了常數級別的額外空間。
程式碼
#include <iostream>
using namespace std;
long long int a;
long long int bs(long long int l,long long int r){
long long int m=(l+r)/2,mm=((1+m)*m)/2;
if(mm==a)return m;
if(l>r)return l;
if(mm>a)
bs(l,m-1);
else
bs(m+1,r);
}
int main(){
while(cin >> a){
if(a<0)a*=-1;
long long int fd=bs(0,a);
while(((fd*(fd+1)/2)-a)%2)
++fd;
cout << fd << "\n";
}
}