Codeforces Round #560 (Div. 3) F2. Microtransactions (hard version)

链接

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

题意

需要购买 $n$ 个物品,每个物品需要 $k_i$ 个。

每个物品原价为 $2$ 元,打折则为 $1$ 元。

现在有 $m$ 个打折信息,每个信息代表某个物品在某日打折。

每天能获得 $1$ 元,求买完所有需要的物品的天数。

思路

贪心策略:若该物品为最后一次打折日,则购买。

二分天数。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <bits/stdc++.h>
#define SZ(x) (int)(x).size()
#define ALL(x) (x).begin(),(x).end()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define FI first
#define SE second
using namespace std;
typedef double DB;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<PII> VPII;
//head
const int N=2e5+5;
int n,m,k[N],sum;
bool st[N];
PII o[N];
bool check(int x) {
for(int i=1;i<=n;i++) st[i]=false;
int tot=0,pre=0x3f3f3f3f;
for(int i=m;i>=1;i--) {
if(o[i].FI>x||st[o[i].SE]) continue;
pre=min(pre,o[i].FI);
int t=min(pre,k[o[i].SE]);
tot+=t;
st[o[i].SE]=true;
pre-=t;
}
return tot+(sum-tot)*2<=x;
}
int solve() {
sort(o+1,o+1+m);
int l=0,r=sum*2;
while(l<r) {
int mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
return l;
}
int main() {
//freopen("E:/OneDrive/IO/in.txt","r",stdin);
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>k[i],sum+=k[i];
for(int i=1;i<=m;i++) cin>>o[i].FI>>o[i].SE;
cout<<solve()<<'\n';
return 0;
}