ZOJ - 3632 DP 单调优化

题意:买瓜,每天的瓜有不同的价格和xu命时间,要求能苟到第n天的最小代价
定义DP方程\(dp[i]\),指苟到第\(i\)天的最小代价,所求即为\(dp[n]\)
那么怎么转移就是问题,这里的状态表示显然不能转移,因为哪一天买的瓜苟到哪一刻都不知道,空间太大不足以维护
再定义一个st表\(st[i]\),表示【能够】苟到第\(i\)天的最小代价,那么转移就是dp[i]=min(dp[i-1]+瓜,st[i...n]),后者表示不买瓜直接xu命
st表肯定是一个每一位都单调非增序列,应该可以用单调队列优化(然而不会),所以还是放到线段树上更新了..

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#include<bitset>
#include<set>
#include<map>
#define rep(i,j,k) for(register int i=j;i<=k;i++)
#define rrep(i,j,k) for(register int i=j;i>=k;i--)
#define erep(i,u) for(register int i=head[u];~i;i=nxt[i])
#define iin(a) scanf("%d",&a)
#define lin(a) scanf("%lld",&a)
#define din(a) scanf("%lf",&a)
#define s0(a) scanf("%s",a)
#define s1(a) scanf("%s",a+1)
#define print(a) printf("%lld",(ll)a)
#define enter putchar('\n')
#define blank putchar(' ')
#define println(a) printf("%lld\n",(ll)a)
#define IOS ios::sync_with_stdio(0)
using namespace std;
const int maxn = 1e5+11;
const int MOD = 2520;
const double eps = 1e-10;
typedef long long ll;
const ll oo = 1ll<<60;
ll read(){
    ll x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
ll dp[maxn],a[maxn],b[maxn],n;
struct ST{
    ll mn[maxn<<2];
    #define lc o<<1
    #define rc o<<1|1
    void build(int o,int l,int r){
        mn[o]=oo;
        if(l==r)return;
        int m=l+r>>1;
        build(lc,l,m);
        build(rc,m+1,r);
    }
    void pu(int o){
        mn[o]=min(mn[lc],mn[rc]);
    }
    void update(int o,int l,int r,int k,ll v){
        if(l==r){
            mn[o]=min(v,mn[o]);
            return;
        }
        int m=l+r>>1;
        if(k<=m) update(lc,l,m,k,v);
        else update(rc,m+1,r,k,v);
        pu(o);
    }
    ll query(int o,int l,int r,int L,int R){
        if(L<=l&&r<=R) return mn[o];
        int m=l+r>>1;
        ll ans=oo;
        if(L<=m) ans=min(ans,query(lc,l,m,L,R));
        if(R>m) ans=min(ans,query(rc,m+1,r,L,R));
        return ans;
    }
}st;
int main(){
    while(cin>>n){
        rep(i,1,n) a[i]=read();
        rep(i,1,n) b[i]=min(read(),n);
        st.build(1,1,n);
        dp[0]=0;
        dp[1]=a[1];st.update(1,1,n,b[1],dp[1]);
        rep(i,2,n){
            dp[i]=dp[i-1]+a[i];
            st.update(1,1,n,min(i+b[i]-1,n),dp[i]);//mai gua
            ll t=st.query(1,1,n,i,n);//xu ming
            if(t<dp[i]) dp[i]=t;
        }
        println(min(dp[n],st.query(1,1,n,n,n)));
    }
    return 0;
}

转载于:https://www.cnblogs.com/caturra/p/8616270.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值