Hello 2023

C. Least Prefix Sum

https://codeforces.com/contest/1779/problem/C

2 seconds / 256 megabytes

standard input / standard output

Problem

Baltic, a famous chess player who is also a mathematician, has an array a1,a2,,an, and he can perform the following operation several (possibly 0) times:

  • Choose some index i (1in);
  • multiply ai with 1, that is, set ai:=ai.
    Baltic's favorite number is m, and he wants a1+a2++am to be the smallest of all non-empty prefix sums. More formally, for each k=1,2,,n it should hold that

a1+a2++aka1+a2++am.

Please note that multiple smallest prefix sums may exist and that it is only required that a1+a2++am is one of them.

Help Baltic find the minimum number of operations required to make a1+a2++am the least of all prefix sums. It can be shown that a valid sequence of operations always exists.

Input

Each test contains multiple test cases. The first line contains the number of test cases t (1t10000). The description of the test cases follows.

The first line of each test case contains two integers n and m (1mn2105) — the size of Baltic's array and his favorite number.

The second line contains n integers a1,a2,,an (109ai109) — the array.

It is guaranteed that the sum of n over all test cases does not exceed 2105.

Output

For each test case, print a single integer — the minimum number of required operations.

Example

Input

6
4 3
-1 -2 -3 -4
4 3
1 2 3 4
1 1
1
5 5
-2 3 -5 1 -20
5 2
-2 3 -5 -5 -20
10 4
345875723 -48 384678321 -375635768 -35867853 -35863586 -358683842 -81725678 38576 -357865873

Output

1
1
0
0
3
4

Note

In the first example, we perform the operation a4:=a4. The array becomes [1,2,3,4] and the prefix sums, [a1, a1+a2, a1+a2+a3, a1+a2+a3+a4], are equal to [1,3,6,2]. Thus a1+a2+a3=6 is the smallest of all prefix sums.

In the second example, we perform the operation a3:=a3. The array becomes [1,2,3,4] with prefix sums equal to [1,3,0,4].

In the third and fourth examples, a1+a2++am is already the smallest of the prefix sums — no operation needs to be performed.

In the fifth example, a valid sequence of operations is:

  • a3:=a3,
  • a2:=a2,
  • a5:=a5.

The array becomes [2,3,5,5,20] and its prefix sums are [2,5,0,5,15]. Note that a1+a2=5 and a1+a2+a3+a4=5 are both the smallest of the prefix sums (and this is a valid solution).

题解

题意

给定一个序列 a1,a2,,an 和下标 m,通过翻转(乘 1)任意位,让第 m 位的前缀和 整个序列的所有前缀和。问最少翻转几次。

思路

对下标 x 进行操作,下标 x 的前缀和大小关系不变

下图为前缀和的折线图,我们对 a2 (即 B 点)进行操作,即 a2 变成 a2.

可以看到变化是 2 的部分整体向下偏移了 2a2,而该部分内部的大小关系没有变化。

这个结论的作用是,我们对下标 x 进行操作,不会改变 x 部分的合法性。若操作前 x 部分的已经符合条件,操作后也是符合条件的。

>0 的元素 ai 进行操作,能让 该元素及其右侧 偏移 2ai

<0 的元素 ai 进行操作,能让 该元素及其右侧 偏移 +2ai.

如下图,我们对 a4(即 D 点)进行操作,可见它及其右侧向下偏移了 2×3=6.

并且,>0 时,若 ai 越大,向下偏移量就越大;<0ai 越小,向上偏移量最大。

由于我们要操作次数最小,根据贪心,我们肯定选的是当前的最值进行操作。(这点非常重要,我就是因为比赛时一直没想到这点,一直陷入错误的思维。没做出来这题的人很多都是这点漏掉了)

对于 m 左侧的区间,如果出现不合法,则对最大的元素进行操作

m 遍历到 1,如果发现第 x 位前缀和不合法(即 presumx<presumm),则寻找 (x,m] 中最大的元素 ai(一定 >0),对其进行操作,操作数 +1.

由于 i<m,所以操作后 am 一定会受到影响而向下偏移 2ai. 我们只需要更新 presumm 即可,因为其他的前缀和大小关系不变,我们用不上就不需要考虑了。

对于 m 右侧的区间,如果出现不合法,则对最小的元素进行操作

m+1 遍历到 n,如果发现第 x 位前缀和不合法(即 presumx<presumm),则寻找 [m+1,n] 中最小的元素 ai(一定 <0),对其进行操作,操作数 +1.

由于 i<x,所以操作后 ax 及其右侧一定会收到影响而向上偏移 2ai. 我们记录一个 offset 变量,即可得知右侧目前偏移了多少。

最大最小值的维护方法

使用 STL 优先队列即可实现

代码

#include <bits/stdc++.h>
#define int long long
#define endl '\n'

using namespace std;

const int MAXN = 2e5 + 10;
int n, m;
int a[MAXN], ps[MAXN];

void solve()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i <= n; i++)
        ps[i] = ps[i - 1] + a[i];
    int psm = ps[m], cnt = 0, offset = 0;
    priority_queue<int> big_heap;
    for (int i = m; i >= 1; i--)
    {
        while (ps[i] < psm + offset)
        {
            cnt++;
            offset -= big_heap.top() * 2;
            big_heap.pop();
        }
        if (a[i] > 0)
            big_heap.push(a[i]);
    }
    priority_queue<int, vector<int>, greater<int>> small_heap;
    offset = 0;
    for (int i = m + 1; i <= n; i++)
    {
        if (a[i] < 0)
            small_heap.push(a[i]);
        while (ps[i] + offset < psm)
        {
            cnt++;
            offset -= small_heap.top() * 2;
            small_heap.pop();
        }
    }
    cout << cnt << endl;
}

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--)
        solve();
    return 0;
}