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