题目链接在这里: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 }