Codeforces Round #560 (Div. 3) Microtransactions

Codeforces Round #560 (Div. 3)

F2. Microtransactions (hard version)

题意:

现在有一个人他每天早上获得1块钱,现在有(n)种商品,每种商品最后需要(k_i)个;现在有(m)个打折信息,每个打折信息包含(d_i,t_i),表示第(t_i)种商品在第(d_i)天打折。如果没有打折的话一个商品卖两块钱,否则卖一块钱。
现在他可以在任意一天买任意多个商品,当然钱要够用,问最少需要多少天才能把所有需要的商品买完。

题解:

其实感觉这个没有多难,二分+贪心就好了。
因为可以在任意一天买任意多个商品,那么我们只需要在每个商品打折的最后一天买就行了,这肯定是最优的。
但怎么确定这里的最后一天,二分一下就行了。答案是满足单调性质的。

代码如下:

#include <bits/stdc++.h>
#define MP make_pair
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 4e5 + 5;
int n, m;
int last[N];
vector <pii> v;
vector <int> Need, days[N];
bool check(int x) {
    memset(last, 0, sizeof(last)) ;
    for(int i = 0; i < m; i++) {
        pii now = v[i] ;
        if(now.first <= x) last[now.second] = max(last[now.second], now.first) ;
    }
    for(int i = 0; i <= x; i++) days[i].clear() ;
    vector <int> k = Need;
    for(int i = 1; i <= n; i++)
        if(last[i] != 0) days[last[i]].push_back(i) ;
    int money = 0;
    for(int i = 1; i <= x; i++) {
        money++;
        if(i > 200000) {
            money += x - i;
            break ;
        }
        for(auto p : days[i]) {
            if(money >= k[p]) {
                money -= k[p] ;
                k[p] = 0;
            } else {
                k[p] -= money ;
                money = 0;
                break ;
            }
        }
    }
    return accumulate(k.begin(), k.end(), 0) * 2 <= money ;
}
int main() {
    ios::sync_with_stdio(false); cin.tie(0) ;
    cin >> n >> m;
    Need.push_back(0) ;
    for(int i = 1; i <= n; i++){
        int tmp;
        cin >> tmp;
        Need.push_back(tmp) ;
    }
    for(int i = 0; i < m; i++) {
        int d, t;
        cin >> d >> t;
        v.push_back(MP(d, t)) ;
    }
    int l = 1, r = 400001, mid ;
    while(l < r) {
        mid = (l + r) >> 1;
        if(check(mid)) r = mid ;
        else l = mid + 1;
    }
    cout << l;
    return 0;
}
原文地址:https://www.cnblogs.com/heyuhhh/p/10877494.html