我是靠谱客的博主 无私狗,最近开发中收集的这篇文章主要介绍ICPC 2020沈阳站 - H. The Boomsday Project(dp,双指针优化),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

https://codeforces.com/gym/103202/problem/H

题意
平常每次租用共享单车花费 r r r 元。
给定 n 种折扣卡,每张折扣卡 c i c_i ci 元,能够在包括购买当天的 d i d_i di 天内免费骑车 k i k_i ki 次。
现在有 m 条使用记录,每条记录给出 p i p_i pi q i q_i qi,表示将会在第 p i p_i pi 天租用单车 q i q_i qi 次。
问,如何购买折扣卡能使得总花费最小,输出最小花费。

1 ≤ n ≤ 500 , 1 ≤ m ≤ 1 0 5 , 1 ≤ r ≤ 1 0 9 1leq n leq 500, 1 leq m leq 10^5, 1 leq r leq 10^9 1n500,1m105,1r109
1 ≤ d i , k i , c i ≤ 1 0 9 1 leq d_i, k_i, c_i leq 10^9 1di,ki,ci109
0 ≤ p i ≤ 1 0 9 , 0 ≤ q i ≤ 3 × 1 0 5 , ∑ i = 1 m q i ≤ 3 × 1 0 5 0 leq p_i leq 10^9, 0 leq q_i leq 3 times 10^5, sum_{i=1}^m q_i leq 3 times 10^5 0pi109,0qi3×105,i=1mqi3×105

思路
注意到 q_i 的数据范围 ∑ i = 1 m q i ≤ 3 × 1 0 5 sum_{i=1}^m q_i leq 3 times 10^5 i=1mqi3×105,可以把每天的 q i q_i qi 次记录铺开,所有的使用记录构成一个数列,表示都在第几天用了,例如:2 2 3 3 3 4 5 5,这样就转化成了 p i ∗ q i p_i*q_i piqi 条记录。
转化之后就和今年蓝桥杯的一道 dp 题(费用报销)类似。

定义状态 f[i] 表示,前 i 条记录的最小花费。

对于当前这一天,遍历所有种类的卡片,从前面找条记录 x 使用当前卡片,能够使得从第 x 条记录开始到当前这条记录都不用花费,那么状态就可以由前 x-1 条记录的花费加上卡片的花费来转移。
因为状态定义的是前 i 条记录的最小花费,那么越靠前花费越小,所以每次找到最靠前的满足条件的位置来转移
因为每种卡片免费的限制条件是使用次数和天数,而此时数组是按照时间排序的,所以对于每种卡片而言,随着遍历记录的后移,最靠前的满足条件的位置也单调往后走,所以可以用一个指针来指,每次遍历一条记录就往后走到转移位置,就省去了遍历转移位置的这一重遍历。

(一开始想在当前记录使用卡片,但是这样就会对后面产生贡献,当前这条记录的状态没办法转移,那么不妨在前面的某条记录使用,能对当前这条记录产生贡献,直接从其前一条记录的状态+卡片花费来转移就行了)

Code

#include<bits/stdc++.h>
using namespace std;

#define Ios ios::sync_with_stdio(false),cin.tie(0)
#define int long long

const int N = 300010, mod = 1e9+7;
int T, n, m;
int r;
struct node{
	int day, cnt, price;
}a[N];
int b[N];
int pos[N];
int f[N];

signed main(){
	Ios;
	cin >> n >> m >> r; 
	
	for(int i=1;i<=n;i++) cin >> a[i].day >> a[i].cnt >> a[i].price;
	
	int idx = 0;
	while(m--)
	{
		int x, y; cin >> x >> y;
		for(int i=1;i<=y;i++) b[++idx] = x;
	}
	sort(b+1, b+idx+1);
	
	for(int i=1;i<=idx;i++) f[i] = 1e18;
	for(int i=1;i<=n;i++) pos[i] = 1;
	
	for(int i=1;i<=idx;i++)
	{
		for(int j=1;j<=n;j++)
		{
			while(pos[j] < i && (b[i] - b[pos[j]] + 1 > a[j].day || i - pos[j] + 1 > a[j].cnt))
				pos[j] ++; //找到第一个满足的位置就停下
			
			f[i] = min(f[i], f[pos[j]-1] + a[j].price); //从其前一位置来转移
		}
	}
	cout << f[idx];
	
	return 0;
}

最后

以上就是无私狗为你收集整理的ICPC 2020沈阳站 - H. The Boomsday Project(dp,双指针优化)的全部内容,希望文章能够帮你解决ICPC 2020沈阳站 - H. The Boomsday Project(dp,双指针优化)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(47)

评论列表共有 0 条评论

立即
投稿
返回
顶部