1. 程式人生 > >洛谷2889 [USACO07NOV]擠奶的時間Milking Time(DP)(樹狀陣列)

洛谷2889 [USACO07NOV]擠奶的時間Milking Time(DP)(樹狀陣列)

題意

奶牛Bessie在0~N時間段產奶。農夫約翰有M個時間段可以擠奶,時間段f,t內Bessie能擠到的牛奶量e。奶牛產奶後需要休息R小時才能繼續下一次產奶,求Bessie最大的擠奶量。
如果在(si,ti)時刻擠奶,那麼休息完的時間是si+r,即下一次可以擠奶的最早時間是(si+r,...)。

題解

DP+樹狀陣列
設f[i]表示在第i小時結束擠奶時收穫的最大奶量。有如下DP方程
f[i]=\max_{0<=j<=i-r}\left\{f[j]\right\}
可以用樹狀陣列解決這個問題。真高興,第一道自己YY出來的樹狀陣列優化DP,儘管很水。

程式碼

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1000010,maxm=1010;

int n,m,r,ans=0;

struct U{int s,t,c;}a[maxm];
bool cmp(U u1,U u2){return u1.s<u2.s;}

int mx[maxn];
void change(int x,int c)
{
    for(;x<=n;x+=x&-x) mx[x]=max(mx[x],c);
}
int findmax(int x)
{
    int re=-(1<<30);
    for(;x>=1;x-=x&-x) re=max(re,mx[x]);
    return re;
}

int main()
{
    scanf("%d%d%d",&n,&m,&r);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&a[i].s,&a[i].t,&a[i].c);
        a[i].s++;a[i].t++;
    }n++;
    sort(a+1,a+m+1,cmp);
    for(int i=1;i<=m;i++)
    {
        int f=findmax(max(a[i].s-r,1))+a[i].c;
        ans=max(ans,f);
        change(a[i].t,f);
    }
    printf("%d\n",ans);
    return 0;
}