暑假集训Day29 H (双指针DP)

题目链接在这里:Problem - H - Codeforces

双指针DP其实就像一个长度可变的滑动窗口,首先因为每一个打折卡都是限定时间和租赁数量的,所以我们把要租的车全部弄开,根据租赁时间从小到大排序,f[i]表示租前i辆车至少要花多少钱,很明显f[i]是递增的,每一次的初始决策是根本不用折扣卡f[i]=f[i-1]+r,然后用折扣卡的话很显然要用一个最小的f[k]来加上c[j],这里k表示能让第j张卡有效的最前面位置,为了不让每次都从头来找这个k,我们用la[j]来存第j张卡上次用的最后位置,这样直接从上一次用的位置往后枚举就行了。

双指针用与n次具有单调性的查找

 1 #include "bits/stdc++.h"
 2 using namespace std;
 3 typedef long long LL;
 4 const int MAX=6e5+5;
 5 LL n,m,r;
 6 struct Node{
 7     LL d,k,c;
 8 }dc[505];
 9 LL sta[MAX];
10 LL f[MAX],la[505];
11 int main(){
12     freopen ("h.in","r",stdin);
13     freopen ("h.out","w",stdout);
14     LL i,j,p,q;
15     scanf("%lld%lld%lld",&n,&m,&r);
16     for (i=1;i<=n;i++){
17         scanf("%lld%lld%lld",&dc[i].d,&dc[i].k,&dc[i].c);
18         la[i]=1;
19     }
20     sta[0]=0;
21     for (i=1;i<=m;i++){
22         scanf("%lld%lld",&p,&q);
23         while (q--){sta[++sta[0]]=p;}
24     }
25     sort(sta+1,sta+sta[0]+1);
26     memset(f,0,sizeof(f));
27     for (i=1;i<=sta[0];i++){
28         f[i]=f[i-1]+r;
29         for (j=1;j<=n;j++){
30             while (sta[la[j]]+dc[j].d-1<sta[i] || la[j]+dc[j].k-1<i) la[j]++;
31             f[i]=min(f[i],f[la[j]-1]+dc[j].c);
32         }
33     }
34     printf("%lld",f[sta[0]]);
35     return 0;
36 }
未来是什么样,未来会发生什么,谁也不知道。 但是我知道, 起码从今天开始努力, 肯定比从明天开始努力, 要快一天实现梦想。 千里之行,始于足下! ——《那年那兔那些事儿》
原文地址:https://www.cnblogs.com/keximeiruguo/p/15227377.html