Problem - C - Codeforces
波罗的海,一个著名的棋手,同时也是一个数学家,他有一个数组a1,a2,...,an,他可以进行以下几次(可能是0次)操作。
选择某个索引i(1≤i≤n)。
将ai与-1相乘,也就是说,设置ai:=-ai。
Baltic最喜欢的数字是m,他希望a1+a2+⋯+am是所有非空前缀之和中最小的一个。更正式地说,对于每一个k=1,2,...,n来说,应该是这样的
a1+a2+⋯+ak≥a1+a2+⋯+am.
请注意,可能存在多个最小的前缀和,只要求a1+a2+⋯+am是其中之一。
帮助Baltic找到使a1+a2+⋯+am成为所有前缀和中最小的一个所需的操作数。可以证明一个有效的操作序列总是存在的。
输入
每个测试包含多个测试案例。第一行包含测试用例的数量t(1≤t≤10000)。测试用例的描述如下。
每个测试用例的第一行包含两个整数n和m(1≤m≤n≤2⋅105)--Baltic数组的大小和他喜欢的数字。
第二行包含n个整数a1,a2,...,an(-109≤ai≤109)--数组。
保证所有测试案例的n之和不超过2⋅105。
输出
对于每个测试用例,打印一个整数--所需操作的最小数量。
例子
InputCopy
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
输出拷贝
1
1
0
0
3
4
注意
在第一个例子中,我们进行操作a4:=-a4。数组变成[-1,-2,-3,4],前缀和[a1, a1+a2, a1+a2+a3, a1+a2+a3+a4],等于[-1,-3,-6,-2]。因此,a1+a2+a3=-6是所有前缀之和中最小的一个。
在第二个例子中,我们进行操作a3:=-a3。数组变成[1,2,-3,4],前缀和等于[1,3,0,4]。
在第三和第四个例子中,a1+a2+⋯+am已经是最小的前缀和了--不需要再进行操作。
在第五个例子中,一个有效的操作序列是。
a3:=-a3。
a2:=-a2。
a5:=-a5。
数组变成[-2,-3,5,-5,20],其前缀和为[-2,-5,0,-5,15]。注意a1+a2=-5和a1+a2+a3+a4=-5都是最小的前缀和(这也是一个有效的解)。
题解:
对于前缀和在k之后的,我们先不用管前面如何,假设前面已经成立,要想让后面的前缀和都大于k
假设k后面数小于0肯定是不行的,所以要维护后面的数加的过程中永远大于等于0,但是可能会有一种情况
999 -999 -1 -1 -1 -1
按理说-999时不用变换,因为结果还是大于等于0,但是对于后面来说要变换两次
如果我们变换-999只要一次就行
所以我们把每次加的数存进multiset里,一旦小于0,就-=2*(*s.begin()),把开头元素删除即可
同理对于k前的元素同一个思想
#include<iostream>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<map>
#include<cstring>
#include<cmath>
#include<stack>
#include<set>
using namespace std;
#define int long long
typedef pair<int,int> PII;
int get(vector<int>a)
{
int res = 0;
multiset<int> s;
int cnt = 0;
for(auto x:a)
{
res += x;
s.insert(x);
while(res < 0)
{
res -= 2*(*s.begin());
cnt ++;
s.erase(s.begin());
}
}
return cnt;
}
void solve()
{
int n,k;
cin >> n >>k;
vector<int> a(n);
for(int i = 0;i < n;i++)
{
cin >> a[i];
}
vector<int> b,c;
for(int i = k;i < n;i++)
{
b.push_back(a[i]);
}
for(int i = k - 1;i > 0;i--)
{
c.push_back(-a[i]);
}
cout << get(b) + get(c)<<"\n";
}
//1 -7 1 -7
signed main(){
// ios::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
int t = 1;
cin >> t;
while(t--)
{
solve();
}
}
//5 2
//3 12