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

孤街醉人 提交于 2020-01-26 15:53:17

 

题意:

一条线段上有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];
}
View Code

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!