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 条件的最后一个midmid为分界点对应得到的值就是x1mid + 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;
    }
}
posted @ 2024-11-14 12:56  PeachyGalaxy  阅读(21)  评论(0编辑  收藏  举报