• G


    题意:

    一条线段上有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
  • 相关阅读:
    oracle中查看sql语句的执行计划
    linux跨主机复制文件
    linux主机登录另一台linux主机
    JVM内存监控:visualVM jconsole jstatd jmap
    linux shell自动输入实现
    awk 截取字符串
    dos2unix dos文本转换为linux文本 /bin/bas^M:bad interpreter
    EasyUI
    Jquery插件 easyUI属性汇总
    移动端省际联动插件mobiscroll
  • 原文地址:https://www.cnblogs.com/bxd123/p/12234275.html
Copyright © 2020-2023  润新知