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;
}
posted @ 2021-09-11 00:12  Tartarus_li  阅读(190)  评论(0编辑  收藏  举报