CF1475D. 清理电话
CF1475D. 清理电话
描述
存在一个数组,每个元素有两个属性 \(a\) 和 \(b\),要求从中选出一些值,\(\sum a>=m\),且 \(\sum b\) 最小,求 \(\sum b\) 最小值。
思路
由于 b 只有1 2 两个值,可以用两个数组分别存 b 属性为 1 和 2 的值,并将其从大到小排序。则要求 \(\sum b\) 最小,就是求这两个数组的前缀。用双指针枚举前缀即可。
代码
#include <bits/stdc++.h>
using namespace std;
int main(){
int t; cin>>t; while(t--){
int n,m; cin>>n>>m;
vector<int> a(n);
vector<int> arr1,arr2;
for(int i=0;i<n;i++) scanf("%d",&a[i]);
for(int i=0;i<n;i++){
int b; scanf("%d",&b);
if(b==1) arr1.push_back(a[i]);
else arr2.push_back(a[i]);
}
sort(arr1.rbegin(),arr1.rend());
sort(arr2.rbegin(),arr2.rend());
int len1=arr1.size(),len2=arr2.size();
long long s=0;
int i=0,j=0;
for(j=0;j<len2;j++){
s+=arr2[j]; if( s>=m||j==len2-1) break;
}
int ans=0x3f3f3f3f;
if(len2==0) j=-1;
if(s>=m)
ans=(j+1)*2;;
for(i=0;i<len1;i++){
s+=arr1[i];
while(j>=0&&s-arr2[j]>=m){
s-=arr2[j]; j--;
}
if(s>=m)
ans=min(ans,(i+1)+(j+1)*2);
}
if(s<m) puts("-1");
else cout<<ans<<endl;
}
return 0;
}