icpc沈阳2020 H. The Boomsday Project (dp+二分)
题目链接:https://codeforces.com/gym/103202/problem/H
\(dp[i]\) 表示前 \(i\) 次租车的最小花费,更新时枚举使用了哪张卡,二分找到能租到哪一次,只更新最后一次租车的 \(dp\) 值即可(之后的 \(dp\) 值都会被这最后一次更新到)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 300010;
const ll INF = 1e18+7;
ll r;
int n, m,tot;
int k[505];
int d[505], c[505];
struct Node{
int p, q;
bool operator < (const Node& t) const {
return p < t.p;
}
}rent[maxn];
int da[maxn];
ll dp[maxn];
int find(int x, int y, int day){
int res = 0;
int l = x, r = min(tot, x + k[y]);
while(l <= r){
int mid = (l + r) / 2;
if(da[mid] <= day+d[y]-1){
res = mid;
l = mid + 1;
} else{
r = mid - 1;
}
}
return res;
}
ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
int main(){
n = read(), m = read(), r = read();
for(int i = 1 ; i <= n ; ++i) d[i] = read(), k[i] = read(), c[i] = read();
tot = 0;
for(int i = 1 ; i <= m ; ++i) {
rent[i].p = read(), rent[i].q = read();
}
sort(rent+1, rent+1+m);
for(int i = 1 ; i <= m ; ++i){
tot += rent[i].q;
for(int j = tot-rent[i].q+1 ; j <= tot ; ++j){
da[j] = rent[i].p;
}
}
for(int i = 0 ; i <= tot ; ++i) dp[i] = INF;
dp[0] = 0;
for(int i = 0 ; i < tot ; ++i){
dp[i+1] = min(dp[i+1], dp[i] + r);
for(int j = 1 ; j <= n ; ++j) {
int pos;
if(i+k[j] <= tot && da[i+k[j]] <= da[i+1]+d[j]-1) pos = i+k[j];
else pos = find(i+1, j, da[i+1]);
dp[pos] = min(dp[pos], dp[i] + c[j]);
}
}
printf("%lld\n", dp[tot]);
return 0;
}