二分找最小絕對值

风掣凧浮發表於2024-11-14

Klee's SUPER DUPER LARGE Array!!!

每次測試時間限制:2秒

每次測試的記憶體限制:256 MB

題目描述

Klee 擁有一個長度為 n 的陣列 a,陣列中的元素依次為 [k, k + 1,..., k + n - 1]。Klee 希望選擇一個索引 i(1≤i≤n),使得 x = |a1 + a2 + ⋯ + ai - ai+1 - ⋯ - an| 最小。其中對於任意整數 z,|z| 表示 z 的絕對值。要求輸出 x 的最小值。

輸入格式

第一行包含 \(t\)\(1 \leq t \leq 10^4\) )—測試用例的數量。

每個測試用例包含兩個整數 \(n\)\(k\)\(2 \leq n, k \leq 10^9\) )—陣列的長度和陣列的起始元素。

輸出格式

對於每個測試用例,在新的一行上輸出 \(x\) 的最小值。

樣例 #1

樣例輸入 #1

4
2 2
7 2
5 3
1000000000 1000000000

樣例輸出 #1

1
5
1
347369930

提示

注意

在第一個示例中, \(a = [2, 3]\) 。當選擇 \(i = 1\) 時, \(x = |2-3| = 1\) 。可以看出,這是 \(x\) 的最小可能值。

在第三個樣本中, \(a = [3, 4, 5, 6, 7]\) 。當選擇 \(i = 3\) 時, \(x = |3 + 4 + 5 - 6 - 7| = 1\) 。可以看出,這是 \(x\) 的最小可能值。






題解

注意到本題中,最後一個樣例過大,而題設的陣列是公差為1的等差數列,很容易想到,等差數列求和公式(死去的高中知識怎麼在攻擊我??)

\[S_n = \frac{n(a_1 + a_n)}{2} ~~~~~ 或者 ~~~~~ S_n = \frac{n[2a_1 + (n-1)d]}{2} \]

#include <iostream> 
using namespace std;

long long n, l, r, mid;
int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		long long k;
		scanf("%d%lld", &n, &k);

		l = 0; r = n;
		long long  ans = 0;
		for (int i = 1; i < n; i++) {
		}
		ans =10 * (n+k);

		while (l <= r) {
			mid = (l + r) >> 1;

			long long sum = 0; int num = 0;
			int nn = n;


			long long add = 0, sub = 0;

			//等差數列求和;死去的記憶正在攻擊我
			add = mid * (2 * k + mid - 1) / 2;
			sub = (n - mid)*(2 * k + n + mid - 1) / 2;

			sum = add - sub;


			long long sum1 = abs(sum);
			if (sum1 <= ans) ans = sum1;


			if (sum > 0) r = mid - 1;
			else l = mid + 1;

		}
		printf("%d\n", ans);
	}
	return 0;
}

相關文章