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