cf round 971 (div.4) E
克利的超大型阵列
题目描述
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)
{
//要寻找满足左边的和 < 右边的和 的最大值,用模板2
long 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;
}
}