POJ 3616 Milking Time dp

http://poj.org/problem?id=3616

题意:

一只牛有m个时间段可以挤奶, 每个时间段能挤出v升奶, 每次挤奶后需要rest分钟休息(然而题意是第7分钟挤完奶, 休息两分钟, 第9分钟就能再次挤奶了....毒瘤题意)

思路:

先说比较好的思路, 毒瘤思路一会再敲...

①正常思路:

将所有的时间段按结束时间从小到大排序, dp[i]表示第i个时间段结束时,得到的最大奶量

枚举第i个时间段和i前结束的所有j时间段, 看是否能更新dp[i].

②毒瘤思路:

将所有的时间段按开始时间从小到大排序

dp[i]表示到i时间时,得到的最大奶量.

dp[i]=max(dp[i],0到i-rest之间最大的dp)

然后开线段树维护区间最大值....

之所以是i-rest而不是i-rest-1是因为毒瘤题意

代码:

//#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fuck(x) std::cout<<"["<<#x<<"->"<<x<<"]"<<endl;
using namespace std;
typedef long long ll;

const ll M=1e6+5;
const ll inf=1e9+5;
const ll mod=1e9+7;
//memset(a,0x3f,sizeof(a));

struct node {
    ll l,r,v;
} a[1005];

ll dp[M];
ll n,m,rest;

bool cmp(node a,node b) {
    if(a.l<b.l)
        return 1;
    else if(a.l>b.l)
        return 0;
    else {
        if(a.r<=b.r)
            return 1;
        else
            return 0;
    }
}

ll sum[4*M];
void pushup(ll i) {
    sum[i] = max(sum[i << 1],sum[i << 1 | 1]);
}

void update(ll l,ll r,ll pos,ll i,ll val) {
    if(l == r && pos == l) {
        sum[i] = val;
        return ;
    }
    ll mid = (l + r) >> 1;
    if(pos <= mid)
        update(l,mid,pos,i << 1,val);
    if(pos > mid)
        update(mid + 1,r,pos,i << 1 | 1,val);
    pushup(i);
}

ll query(ll l,ll r,ll ql,ll qr,ll i) {
    if(ql <= l && r <= qr)
        return sum[i];
    ll ans = -1;
    ll mid = (l + r) >> 1;
    if(ql <= mid)
        ans = max(ans,query(l,mid,ql,qr,i << 1));
    if(qr > mid)
        ans = max(ans,query(mid + 1,r,ql,qr,i << 1 | 1));
    return ans;
}




int main() {
    memset(dp,0,sizeof(dp));
    scanf("%lld%lld%lld",&n,&m,&rest);
    for(ll i=0; i<m; i++) {
        scanf("%lld%lld%lld",&a[i].l,&a[i].r,&a[i].v);
    }
    sort(a,a+m,cmp);
    for(ll i=0; i<m; i++) {
        ll l=a[i].l,r=a[i].r,v=a[i].v;
        if(l-rest<0) {
            if(dp[r]<v) {
                dp[r]=v;
                update(0,n,r,1,dp[r]);
            }
        } else {
            ll _max=query(0,n,1,l-rest,1);
            if(dp[r]<_max+v) {
                dp[r]=_max+v;
                update(0,n,r,1,dp[r]);
            }
        }
    }
    ll ans=0;
    for(int i=0;i<=n;i++){
        ans=max(ans,dp[i]);
    }
    printf("%lld\n",ans);
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值