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;
}