Codeforces Round #697 (Div. 3) D. Cleaning the Phone (思维,前缀和)
- 题意:你的手机有\(n\)个app,每个app的大小为\(a_i\),现在你的手机空间快满了,你需要删掉总共至少\(m\)体积的app,每个app在你心中的珍惜值是\(b_i\),\(b_i\)的取值为\(1\)或\(2\),现在问你至少删掉体积\(m\)的app的最小珍惜值是多少,如果不能满足条件,输出\(-1\).
- 题解:因为\(b_i\)的取值只有\(1\)和\(2\),所以我们肯定优先选珍惜值\(1\)的体大的app,这样贪心的话,我们将\(1\)和\(2\)分开,从大排序,记录\(1\)和\(2\)的前缀和,枚举\(1\)的前缀和然后再去二分找\(2\)的前缀和,判断是否合法维护答案的最小值即可.
- 代码:
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
int _;
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>_;
while(_--){
int n,m;
cin>>n>>m;
vector<ll> a(n);
vector<int> b(n);
ll sum=0;
for(auto &w:a){
cin>>w;
sum+=w;
}
for(auto &w:b) cin>>w;
if(sum<m) {cout<<-1<<'\n';continue;}
vector<ll> _1;
vector<ll> _2;
rep(i,0,n-1){
int x=a[i];
int y=b[i];
if(y==1) _1.pb(x);
else _2.pb(x);
}
sort(_1.rbegin(),_1.rend());
sort(_2.rbegin(),_2.rend());
vector<ll> _pre2;
_pre2.pb(0);
rep(i,0,(int)_2.size()-1) _pre2.pb(_pre2[i]+_2[i]);
int len=_pre2.size();
sum=0;
ll ans=1e18;
int cur=lower_bound(_pre2.begin(),_pre2.end(),m)-_pre2.begin();
if(cur!=len) ans=cur*2;
rep(i,0,(int)_1.size()-1){
sum+=_1[i];
if(sum>=m){
ans=min(ans,1ll*i+1);
break;
}
ll cur=m-sum;
int it=lower_bound(_pre2.begin(),_pre2.end(),cur)-_pre2.begin();
if(it!=len) ans=min(ans,i+1+2*1ll*it);
}
cout<<ans<<'\n';
}
return 0;
}
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮