传送门
二分出每个点不需要付www贡献的范围,然后可以推出转移式子:
f[i][j]=f[i−1][k]+value(k+1,j)+c[i]f[i][j]=f[i-1][k]+value(k+1,j)+c[i]f[i][j]=f[i−1][k]+value(k+1,j)+c[i],把c[i]c[i]c[i]提出来发现前面的可以用线段树优化转移。
于是每次选一个数相当于区间加,再维护一个区间查询最小值转移就行了。
代码:
#include<bits/stdc++.h>
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1)
using namespace std;
const int N=2e4+5,M=105;
int n,K,d[N],s[N],sum[N],w[N],c[N],ans;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
vector<int>q[N];
struct Node{int l,r,add,mn;}T[N<<2];
struct Seg{int l,r;}p[N];
inline void pushup(int p){T[p].mn=min(T[lc].mn,T[rc].mn);}
inline void pushnow(int p,int v){T[p].mn+=v,T[p].add+=v;}
inline void pushdown(int p){if(T[p].add)pushnow(lc,T[p].add),pushnow(rc,T[p].add),T[p].add=0;}
inline void build(int p,int l,int r){
T[p].l=l,T[p].r=r,T[p].add=0;
if(l==r){T[p].mn=sum[l];return;}
build(lc,l,mid),build(rc,mid+1,r),pushup(p);
}
inline void update(int p,int ql,int qr,int v){
if(ql>T[p].r||qr<T[p].l)return;
if(ql<=T[p].l&&T[p].r<=qr)return pushnow(p,v);
pushdown(p);
if(qr<=mid)update(lc,ql,qr,v);
else if(ql>mid)update(rc,ql,qr,v);
else update(lc,ql,mid,v),update(rc,mid+1,qr,v);
pushup(p);
}
inline int query(int p,int ql,int qr){
if(ql>T[p].r||qr<T[p].l)return 2e9;
if(ql<=T[p].l&&T[p].r<=qr)return T[p].mn;
pushdown(p);
if(qr<=mid)return query(lc,ql,qr);
if(ql>mid)return query(rc,ql,qr);
return min(query(lc,ql,mid),query(rc,mid+1,qr));
}
int main(){
n=read(),K=read();
for(int i=2;i<=n;++i)d[i]=read();
for(int i=1;i<=n;++i)c[i]=read();
for(int i=1;i<=n;++i)s[i]=read();
for(int i=1;i<=n;++i)w[i]=read();
for(int i=1,l,r,pos;i<=n;++i){
l=1,r=i-1,pos=i;
while(l<=r){
int Mid=l+r>>1;
if(d[i]-d[Mid]<=s[i])r=Mid-1,pos=Mid;
else l=Mid+1;
}
p[i].l=pos,l=i+1,r=n,pos=i;
while(l<=r){
int Mid=l+r>>1;
if(d[Mid]-d[i]<=s[i])l=Mid+1,pos=Mid;
else r=Mid-1;
}
p[i].r=pos;
}
for(int i=1;i<=n;++i)q[p[i].r].push_back(i);
for(int i=1,pre=0;i<=n+1;++i){
sum[i]=pre+c[i];
for(int j=q[i].size()-1;~j;--j)pre+=w[q[i][j]];
}
ans=sum[n+1];
for(int i=1;i<=K;++i){
build(1,1,n+1);
for(int j=1;j<=n+1;++j){
sum[j]=query(1,1,j-1)+c[j];
for(int k=0;k<q[j].size();++k)update(1,1,p[q[j][k]].l-1,w[q[j][k]]);
}
ans=min(ans,sum[n+1]);
}
cout<<ans;
return 0;
}