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<<'
';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<<'
';

	}

    return 0;
}
原文地址:https://www.cnblogs.com/lr599909928/p/14342709.html