zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Tire树的理解和应用
    C语言:socket简单模拟http请求
    C语言:关于socket的基础知识点
    php中的ip2long和long2ip的理解
    理解php中的pack/unpack/ord/chr
    zlog学习笔记(mdc)
    计算机工作的进行
    期末总结
    第十四周学习报告
    第十三周学习报告
  • 原文地址:https://www.cnblogs.com/A-LEAF/p/7737730.html
Copyright © 2011-2022 走看看