克利的超大型阵列
题目描述
Klee 有一个长度为 \(n\) 的数组 \(a\) ,数组中依次包含整数 \([k, k+1, ..., k+n-1]\) 。克利希望选择一个索引 \(i\) ( \(1 \leq i \leq n\) ),使得 \(x = |a_1 + a_2 + \dots + a_i - a_{i+1} - \dots - a_n|\) 最小。请注意,对于任意整数 \(z\) 而言, \(|z|\) 表示 \(z\) 的绝对值。
输出 \(x\) 的最小可能值。
输入
第一行包含 \(t\) ( \(1 \leq t \leq 10^4\) ) - 测试用例数。
每个测试用例包含两个整数 \(n\) 和 \(k\) ( \(2 \leq n, k \leq 10^9\) ) - 数组的长度和数组的起始元素。
输出
对于每个测试用例,另起一行输出 \(x\) 的最小值。
样例
4
2 2
7 2
5 3
1000000000 1000000000
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\) 的最小可能值。
思路
设mid以及左边所有数之和为s1
,右边所有数之和为s2
x的最小值只可能在(s1 - s2)的正负边界
出现 -> (s1 - s2)= x1 最后一次为负数 || (s1 - s2) = x2 第一次为正数
寻找到符合 s1 < s2 条件的最后一个mid
,mid
为分界点对应得到的值就是x1;mid + 1
为分界点对应得到的值就是x2
最后 $$x = min ( abs ( x1 ) , abs ( x2 ) )$$
代码实现
#include <iostream>
#include <algorithm>using namespace std;int main()
{long long t; cin >> t;while(t--){long long n, k;cin >> n >> k;long long l = 1, r = n + 1, s1, s2, sum = n * (2 * k + n - 1) / 2;while(l < r){ //要寻找满足左边的和 < 右边的和 的最大值,用模板2long long mid = l + r + 1 >> 1;s1 = (2 * k + mid - 1) * mid / 2;s2 = sum - s1;if(s1 <= s2) l = mid;else r = mid - 1;} long long left = ((2 * k + l - 1) * l) / 2, right = sum - left; //负边界long long le = ((2 * k + l) * (l + 1)) / 2, ri = sum - le; //正边界cout << min(abs(left - right), abs(le - ri)) << endl;}
}