Codeforces 1165F Microtransactions

Codeforces 1165F Microtransactions

题目链接

https://codeforces.com/contest/1165/problem/F2

题目大意

你需要购买 $n$ 个物品,每个需要购买 $k_i$ 个。你每天会获得 $1 \ burle$,每个物品价值 $2 \ burles$,有 $m$ 个促销活动,其中 $d_i$ 天 $t_i$ 物品价格会变成 $1 \ burle$,问最少多少天收集齐所有的物品。

题目分析

考虑如果问 $x$ 天时间,问是否可以买完所有需要的物品。从前往后扫描显然会出现钱不够不知道该买谁的情况,考虑从后往前扫描,那么每过一天获得的 $burle$ ,直接购买有必要购买的即可,因为前面节省下来的钱,后面肯定可以用。

解决了这个问题那么就很容易了,它已经具备了二分答案的先决条件了,直接二分即可。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>

using namespace std;

const int maxn = 2e5 + 5;

int n, m, t;

int a[maxn];
int b[maxn];

struct ex {
	int d, t;
};

vector <ex> vec;

bool cmp(ex x, ex y){
	return x.d > y.d;
}

int read(){
	int x;
	scanf("%d", &x);
	return x;
}

bool check(int x){
	int i, j = 0;
	int cnt = 0, sum = 0;
	queue <ex> q;
	
	for(i=1;i<=n;i++){
		b[i] = a[i];
		sum += b[i];
	}
	
	for(ex tmp : vec){
		if(tmp.d > x)continue;
		q.push(tmp);
	}
	
	for(i=x;i>0;i--){
		while(q.size() and !b[q.front().t])q.pop();
		if(q.size() and q.front().d >= i){
			b[q.front().t]--;
			cnt++;
		}
	}
	
	return x - cnt >= 2 * (sum - cnt);
}

int main(){
	int i, j;
	int x, y;
	int l = 0, r;
	
	n = read();
	m = read();
	
	for(i=1;i<=n;i++){
		a[i] = read();
		l += a[i];
	}
	
	for(i=1;i<=m;i++){
		x = read();
		y = read();
		vec.push_back({x, y});
	}
	
	sort(vec.begin(), vec.end(), cmp);
	
	r = 2 * l;
	
	while(l < r){
		int mid = (l + r) / 2;
		if(!check(mid)){
			l = mid + 1;
		}else{
			r = mid;
		}
	}
	
	printf("%d\n", l);
	
	return 0;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据