题目:
思路:
可以分3种情况讨论,
1、k = m,这种情况是一定满足 a 1 a_1 a1 + a 2 a_2 a2 + … + a k a_k ak > = >= >= a 1 a_1 a1 + a 2 a_2 a2 + … + a m a_m am。
2、k < m,这种情况要想满足题中条件,则必须
a
k
a_k
ak
+
_+
+
1
_1
1 +
a
k
a_k
ak
+
_+
+
2
_2
2 + … +
a
m
a_m
am
<
=
<=
<= 0。
定义tmp =
a
k
a_k
ak
+
_+
+
1
_1
1 +
a
k
a_k
ak
+
_+
+
2
_2
2 + … +
a
m
a_m
am.
解决这种情况,可以从k = m - 1,到 k = 1进行遍历,用一个优先队列 priority_queue o1(定义 u=o1的堆顶元素) 存储遍历过的所有大于0的数,
当tmp > 0是取出队列o1中的堆顶元素,tmp -= 2 * u,ans += 1;
3、k > m,这种情况要想满足题中条件,则必须
a
m
a_m
am
+
_+
+
1
_1
1 +
a
m
a_m
am
+
_+
+
2
_2
2 + … +
a
k
a_k
ak
>
=
>=
>= 0。
定义tmp =
a
m
a_m
am
+
_+
+
1
_1
1 +
a
m
a_m
am
+
_+
+
2
_2
2 + … +
a
k
a_k
ak.
解决这种情况,可以从k = m + 1,到 k = n进行遍历,用一个优先队列 priority_queue o2(定义 u=o2的堆顶元素) 存储遍历过的所有小于0的相反数,
当tmp < 0是取出队列o1中的堆顶元素,tmp += 2 * u,ans += 1;
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[200005] = { 0 };
int n,m;
int main()
{
int _;
scanf("%d",&_);
while (_--)
{
priority_queue<int> o1;
priority_queue<int> o2;
scanf("%d%d",&n,&m);
for (int i = 1; i <= n; i++) scanf("%d",&a[i]);
int ans = 0;
ll tmp = 0;
for (int i = m; i > 1; i--){
tmp += a[i];
if (a[i] > 0) o1.push(a[i]);
while (tmp > 0){
int u = o1.top();o1.pop();
tmp -= 2 * u;
ans++;
}
}
tmp = 0;
for (int i = m + 1; i <= n; i++) {
tmp += a[i];
if (a[i] < 0) o2.push(-a[i]);
while (tmp < 0 ){
int u = o2.top();o2.pop();
tmp += 2 * u;
ans++;
}
}
printf("%d\n",ans);
}
return 0;
}