G - Most Dangerous Shark dp 单调栈 单调队列

题意:

一条线段上有n张骨牌(n=1e7), 相邻骨牌距离为1,每张骨牌有其高度和推倒的花费,问最少的花费推倒所有的骨牌。

题解:

  • 首先用单调栈维护每个位置往左(右)推能推倒的最远的骨牌
  • dp[i]表示1-i倒下的最小花费
  • 转移显然只有两种  一种是第i张往左推动
  • 另一种是找到往右推动能推倒i的最小花费的地方进行转移  这里可以用单调栈维护最小值

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e7+1000;

ll n,m,siz[N],h[N],L[N],R[N],c[N],dp[N];
vector<ll>H[N],C[N];
int s[N],r;

int main() {
    cin>>n>>m;
    for(int i=1;i<=n;i++) {
        scanf("%lld",&siz[i]);
        H[i].resize(siz[i]);
        C[i].resize(siz[i]);
        for(int j=0;j<siz[i];j++) scanf("%lld",&H[i][j]);
        for(int j=0;j<siz[i];j++) scanf("%lld",&C[i][j]);
    }
    int Q;cin>>Q;
    int cnt=0;
    while(Q--) {
        int id,mul;scanf("%d%d",&id,&mul);
        for(int j=0;j<siz[id];j++) h[++cnt]=H[id][j],c[cnt]=C[id][j]*mul;
    }
    for(int i=1;i<=m;i++) {
        while(r&&h[s[r]]+s[r]<=i)
            R[s[r--]]=i-1;
        s[++r]=i;
    }
    while(r) R[s[r--]]=m;
    for(int i=m;i;i--) {
        while(r&&s[r]-h[s[r]]>=i)
            L[s[r--]]=i+1;
        s[++r]=i;
    }
    while(r) L[s[r--]]=1;

    for(int i=1;i<=m;i++) {
        dp[i]=c[i]+dp[L[i]-1];
        while(r&&R[s[r]]<i) r--;
        if(r) dp[i]=min(dp[i],c[s[r]]+dp[s[r]-1]);
        ll cost=c[i]+dp[i-1];
        if(r&&cost<c[s[r]]+dp[s[r]-1]||!r)
            s[++r]=i;
    }
    cout<<dp[m];
}

原文地址:https://www.cnblogs.com/bxd123/p/12234275.html

时间: 2024-10-11 05:46:16

G - Most Dangerous Shark dp 单调栈 单调队列的相关文章

单调栈 、 队列学习

推荐博客 :https://blog.csdn.net/zuzhiang/article/details/78134247 单调栈.队列只需满足两个条件即可,序列是单调的,并且符合栈和队列的特性. 实现: 例如实现一个单调递增的栈,比如现在有一组数10,3,7,4,12.从左到右依次入栈,则如果栈为空或入栈元素值小于栈顶元素值,则入栈:否则,如果入栈则会破坏栈的单调性,则需要把比入栈元素小的元素全部出栈.单调递减的栈反之. 10入栈时,栈为空,直接入栈,栈内元素为10. 3入栈时,栈顶元素10比

7.14 单调栈 单调队列 +dp优化

单调栈和单调队列的定义具体看ppt了 模板: 单调队列 head =1; tail = 0; rep( i ,1 ,n ){ while( head <= tail && a[i] < dq[tail].first)tail--; while( head <= tail && dq[head].second < i-k+1) head++; dq[ ++tail ]={a[i] ,i}; 例题:https://vjudge.net/contest/3

小结:单调栈 &amp; 单调队列

概要: 对于维护信息具有单调性的性质或者问题可以转化为具有单调性质的模型的题,我们可以考虑用单调栈或单调队列. 技巧及注意: 技巧很多,只要能将问题转化为单调性问题,就好解决了. 当维护固定长度的单调区间,我们考虑用单调队列,如[BZOJ]3314: [Usaco2013 Nov]Crowded Cows(单调队列) 单调栈维护长度时要进行及时更新,例如:[BZOJ]3039: 玉蟾宫(DP/单调栈) 假设完美状态后再进行减法原理,例如:[BZOJ]1628 && 1683: [Usaco

数据结构之单调栈单调队列模板

单调栈 int rear=0; for(int st=1;st<=N;st++) { while(rear>0&&H[que[rear]]>=H[st]) --rear; if(rear==0) le[st]=0; else le[st]=que[rear]; que[++rear]=st; } 单调队列 int que[maxn],elem[maxn]; int front=1,rear=0; for(int i=1;i<K;i++) { while(rear&g

单调栈&amp;单调队列入门

单调队列是什么呢?可以直接从问题开始来展开. Poj 2823 给定一个数列,从左至右输出每个长度为m的数列段内的最小数和最大数. 数列长度:\(N <=10^6 ,m<=N\) 解法① 很直观的一种解法,那就是从数列的开头,将窗放上去,然后找到这最开始的k个数的最大值,然后窗最后移一个单元,继续找到k个数中的最大值. 这种方法每求一个f(i),都要进行k-1次的比较,复杂度为$ O(Nk) $. 显然,如果暴力时间复杂度为 $ O(Nm) $ 不超时就怪了. 解法② 还有一种想法是维护一个B

单调栈&amp;单调队列

最近打了三场比赛疯狂碰到单调栈和单调队列的题目,第一,二两场每场各一个单调栈,第三场就碰到单调队列了.于是乎就查各种博客,找单调栈,单调队列的模板题去做,搞着搞着发现其实这两个其实是一回事,只不过利用了容器内元素单调的不同特性,用来加速处理不同的问题. 单调栈解决的是以某个值为最小(最大)值的最大区间,维护的是左右两边第一个比当前位大或者小的数 单调队列解决的是区间最小(最大)值,维护的是区间内的最值 举个栗子,a[i] = { 1,6,3,5,1,2,4 } 如果容器内数字是单调递减的,最后得

数据结构——单调栈&amp;单调队列(解决滑动窗口问题)

单调队列解答: /*******************单调队列!=优先队列单调队列是为了保证队列内的元素具有单调性,在保持了元素原本顺序的同时,对元素进行了过滤,舍弃了会影响单调性的元素而优先队列本质上还是个队列不会舍弃任何元素,每个元素都在队列之中,但是在队列中的位置由优先队列定义的优先级来确定,损失了原数组中的数据相对位置关系.所以很显然,单调队列是解决:寻找在某元素左侧区间或者右侧区间的最值问题,而优先队列的应用是寻找整个区间内的最高优先级别的内容./******************

单调栈/单调队列/RMQ

在上上周的交友大会中,队长大人提到了st算法,然后仔细的发呆了一个星期,于是就开始做队长的专题了, 6天后的我总算在此专题做题数目和队长一样了..明早没课,准备通宵把这几天的零散的记忆整理一下. HDU 3530 Subsequence 一开始想为何不能m和k一起放到while语句里进行处理 nowmax和nowmin保存了i之前的最大和最小值,假设此时已经出现不满足k和m的序列(A)了(比k大or比m小or both),然后我们往后找,发现了一个比序列(A)的min更小的值(me),此时now

单调栈 &amp; 单调队列

一. 二.单调队列 1 inline int FindMax() 2 { 3 int ans=-0x3f3f3f3f; 4 Q.push_back(0); //Q放置的是下标 5 for(int i=1;i<=n;i++) 6 { 7 while(!Q.empty()&&Q.front()<i-m)Q.pop_front(); //判断是否超出左边界 8 ans=max(ans,s[i]-s[Q.front()]); // 不断更新答案 9 while(!Q.empty()&a