bzoj_4639_博士的选取器

$f_{i} 到第i位最少的花费 $

$n^2dp$ 很容易想

考虑优化

首先把权值从大到小排序,把pos压进set里

处理出每一个位置 i 前面第一个大于等于v[i]的位置

$$ f_{i}=min( f_{k}+max(v[l])(l+1<=k<=i) ) $$

用线段树优化

但是你并不知道v[i]控制到哪段区间,这时候,预处理的东西就用到了

我们来维护$v_{i}$能控制的一段区间的v的最大值

再维护区间$f_{i}$的最小值

就可以$O(nlogn)$ 转移了

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <set>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define rint register int
using namespace std;
inline void read(int &x)
{
    x=0; char q=getchar();
    while(q<'0'||q>'9') q=getchar();
    while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar();
}
const int N=300006;

struct JI
{
    int pos,val;
    bool friend operator < (JI a,JI b)
    {
        return a.val>b.val;
    }
}ji[N];

int INF=(1<<30);

set<int> q;
int n,limit;
int v[N],f[N],pr[N];

int smn[N<<2],fmn[N<<2],vmx[N<<2],mk[N<<2];
void pushup(int x)
{
    smn[x]=min(smn[x<<1],smn[x<<1|1]);
    fmn[x]=min(fmn[x<<1],fmn[x<<1|1]);
    vmx[x]=max(vmx[x<<1],vmx[x<<1|1]);
}
void pushdown(int x)
{
    if(mk[x])
    {
        if(mk[x<<1]<mk[x]) mk[x<<1]=mk[x];
        if(mk[x<<1|1]<mk[x]) mk[x<<1|1]=mk[x];
        smn[x<<1]=fmn[x<<1]+mk[x];
        smn[x<<1|1]=fmn[x<<1|1]+mk[x];
        if(vmx[x<<1]<mk[x]) vmx[x<<1]=mk[x];
        if(vmx[x<<1|1]<mk[x]) vmx[x<<1|1]=mk[x];
        mk[x]=0;
    }
}
void build(int l,int r,int x)
{
    if(l==r)
    {
        if(!l) smn[x]=fmn[x]=0;
        else smn[x]=fmn[x]=INF;
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,x<<1);
    build(mid+1,r,x<<1|1);
    pushup(x);
}
void add(int L,int R,int vv,int l,int r,int x)
{
    if(L<=l&&r<=R)
    {
        mk[x]=max(mk[x],vv);
        if(vmx[x]<vv) vmx[x]=vv;
        smn[x]=fmn[x]+vmx[x];
        return ;
    }
    pushdown(x);
    int mid=(l+r)>>1;
    if(L<=mid) add(L,R,vv,l,mid,x<<1);
    if(mid<R) add(L,R,vv,mid+1,r,x<<1|1);
    pushup(x);
}
void addf(int pos,int vv,int l,int r,int x)
{
    if(l==r)
    {
        if(fmn[x]>vv) fmn[x]=vv;
        smn[x]=fmn[x]+vmx[x];
        return ;
    }
    pushdown(x);
    int mid=(l+r)>>1;
    if(pos<=mid) addf(pos,vv,l,mid,x<<1);
    else addf(pos,vv,mid+1,r,x<<1|1);
    pushup(x);
}
void qq(int L,int R,int &an,int l,int r,int x)
{
    if(L<=l&&r<=R)
    {
        if(an>smn[x]) an=smn[x];
        return ;
    }
    pushdown(x);
    int mid=(l+r)>>1;
    if(L<=mid) qq(L,R,an,l,mid,x<<1);
    if(mid<R) qq(L,R,an,mid+1,r,x<<1|1);
    pushup(x);
}

int main(){
    
    //freopen("in.in","r",stdin);
    
    rint i,j;
    
    read(n); read(limit);
    for(i=1;i<=n;++i)
        read(v[i]),ji[i].val=v[i],ji[i].pos=i;
    sort(ji+1,ji+1+n);
    set<int> :: iterator it;
    int now;
    for(i=1;i<=n;i=now+1)
    {
        now=i;
        while(ji[now].val==ji[i].val&&now<=n) ++now; --now;
        for(j=i;j<=now;++j)
            q.insert(ji[j].pos);
        for(j=i;j<=now;++j)
        {
            it=q.find(ji[j].pos);
            if(it==q.begin())
                pr[ji[j].pos]=0;
            else
                --it,pr[ji[j].pos]=*it;
        }
    }
    build(0,n,1);
    int l=0,sum=0,tt,vv;
    for(i=1;i<=n;++i)
    {
        sum+=v[i];
        while(sum>limit&&l<i) sum-=v[l],++l;
        tt=max(pr[i],l-1);
        add(tt,i-1,v[i],0,n,1);
        vv=INF;
        qq(max(l-1,0),i-1,vv,0,n,1);
        f[i]=vv;
        addf(i,f[i],0,n,1);
    }
    cout<<f[n];
}
AA

 

posted @ 2017-10-26 16:58  A_LEAF  阅读(258)  评论(0编辑  收藏  举报