这题是原来cf上的一道原题,不过对于有一些数据范围修改了,不过还是很好想的
题意:给定一个长度为N的数组,对于数组中的每个位置,满足当前和小于M所需要去掉的最小代价
分析:对于当前是否需要进行去掉一些值,可以采取贪心的方法,对每次加入进来的数进行排序,当前是否需要删除一些值取决于当前的所有值的和,当超过M时,贪心的去除最大的,不过对于当前情况需要去掉多少个才能将该元素加入,不过考虑到对于后面元素的影响,所以去掉的不一定是之前的元素,我们真正要去掉的是将元素加入之后的值。
具体原因如下:当加入的值比当前保存值的最大值小的时候,考虑到后面的元素如果需要进行删除操作,删除当前加入的值一定比删除当前保存值的最大值优,所以需要将后面的元素删除。当加入的值比当前保存值的最大值大或相等时,删去谁都可以,故此时保证答案的正确性。
具体使用mutiset来维护,multiset是<set>库中一个非常有用的类型,它可以看成一个序列,插入一个数,删除一个数都能够在O(logn)的时间内完成,所以很优秀,使用也很方便
具体代码:
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+7; int a[maxn]; multiset<int>ss; int main() { int t; scanf("%d",&t); while(t--) { ss.clear(); long long int n,m; scanf("%lld%lld",&n,&m); for(int i=0;i<n;i++) { scanf("%d",&a[i]); } long long int sum=0; int tem=0; for(int i=0;i<n;i++) { long long int suma=sum; int jishu=0; if(suma+a[i]>m) { auto j=ss.end(); while(suma+a[i]>m) { j--; suma-=*j; jishu++; } } printf("%d ",jishu+tem); ss.insert(a[i]); auto j=ss.end(); sum+=a[i]; while(sum>m) { j--; sum-=*j; ss.erase(ss.find(*j)); tem++; } } printf(" "); } }