🚀前言 🚀
大家好啊,这里是幸麟
🧩 一名普通的大学牲,最近在学习算法
🧩每日一题的话难度的话是根据博主水平来找的
🧩所以可能难度比较低,以后会慢慢提高难度的
🧩此题标签:*1500 数据结构 贪心
🧩本文栏目:一起来打cf吧
期待各位的点赞+收藏+关注,订阅专栏,每天一起写一道cf吧
一起学习算法吧
往期链接:
B. Coloring—codeforces每日一题http://t.csdn.cn/eEkkb
N. Number Reduction—codeforces每日一题 http://t.csdn.cn/jCLEg
E. Easy Assembly—codeforces每日一道思维题2 http://t.csdn.cn/pNrCd
codeforces每日一题1-Absolute Sorting http://t.csdn.cn/mCL6Y
题目
题目:
题目大意:
Baltic有一个数组a,里面的元素个数是n,因为他喜欢数字m(1<=m<=n<2e5+10),所以他希望a1+a2+a3.....+am<a1+a2....+ak(1<=k<=n)
为实现他的希望,他可以进行以下的操作(也可以不进行)
选中数组其中一个元素的下标i,令a[i]=-a[i];
请问他至少进行多少次操作才能实现a1+a2+a3.....+am<a1+a2....+ak(1<=k<=n)
输入:每个测试用例的第一行包含两个整数 n和m(1≤m≤n≤2⋅105) — Baltic数组a的大小和他最喜欢的数字。
第二行包含 n个整数
保证 n 的和
在所有测试用例中不超过 2⋅105
输出:每一个用例最小的操作数
往下面翻就是答案了(想继续思考的话,还是不要往下面翻了)
思路+答案
既然想要实现a1+a2+a3.....+am<a1+a2....+ak(1<=k<=n)
我们令sum[i]为a1+a2+a3.....+ai
假设,i<=m 此时我们令a[i+1]+a[i+2]...+a[m]为subsum(你可以理解为sum[m]-sum[i])
如果有subsum<=0,那么sum[m]<=sum[i]
如果对于任何一个i<m有subsum<=0,那么就有sum[m]<=sum[i](1<=i<=m)
那么要实现这一部分,我们就要维护这个subsum,使其永远<=0即可
那么只要每次出现subsum>0的情况,我们需要减去我们之前遍历过的最大的正数(因为操作数要最小,所以我们尽量减去最大的正数,这里我使用了优先队列)
那么经过如上操作我们就使用了最少的操作数完成了前半部分a1+a2+a3.....+am<a1+a2....+ak(1<=k<=m)
那么后半部分我们也同理,详情可以看一下代码,上面讲的可能有点抽象了
#include <iostream>
#include <queue>
#include <map>
#include <unordered_map>
#include <vector>
#include <algorithm>
#include <cmath>
#include <string>
#include <cstring>
#include <set>
using namespace std;
typedef long long ll;
const int N=2e5+10;
ll a[N];
int main()
{
int t;
cin>>t;
while(t--)
{
priority_queue<ll> q1;
priority_queue<ll> q2;
int n,m;
int ans=0;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%lld",a+i);
}
if(n==1)
{
cout<<0<<"\n";
continue;
}
ll subsum=0;
for(int i=m;i>1;i--)
{
subsum=subsum+a[i];
if(a[i]>0)
{
q1.push(a[i]);
}
if(subsum>0)
{
ans++;
subsum=subsum-2*q1.top();
q1.pop();
}
}
ll addsum=0;
for(int i=m+1;i<=n;i++)
{
addsum+=a[i];
if(a[i]<0)
{
q2.push(-a[i]);
}
if(addsum<0)
{
ans++;
ll num=q2.top();
addsum+=2*num;
q2.pop();
}
}
cout<<ans<<'\n';
}
return 0;
}
好了,今天的每日一题到此结束了,有些地方说的可能不太清楚,如果有疑惑欢迎在评论区留言
一起讨论一下,最近会继续写题目,但是不会更新这个系列了,等期末考结束再来吧