哇..假的假的…好难….
为什么…这么多道题..我要先看这道……….
我以为第一道会很和蔼的啊啊啊
唉…
其实..简单来说就是线段树优化dp….但是…依旧不会啊扎心
方程其实也是可以写的
f(i,j)=f(k,j−1)+cost(k+1,i−1)+c[i],f(i,j)
f
(
i
,
j
)
=
f
(
k
,
j
−
1
)
+
c
o
s
t
(
k
+
1
,
i
−
1
)
+
c
[
i
]
,
f
(
i
,
j
)
表示在第i个点建立第j个通讯基站
然后去想怎么优化….cost..是最难求的…
每个点会有一个覆盖区域,那我们可以预处理求出来他的左右端点
右端点为i的时候,在i+1的时候右边显然就不能被覆盖了,那么如果上一个基地建在他的左端点的右边,那么他就再也不能被覆盖了。因此在线段树中左端点右边的位置加上他的不能被覆盖值
每一个
f(i,j)
f
(
i
,
j
)
也就是前面最小的..线段树求个最小值就好啦
注:因为我们无法判断最后一个建在哪里,所以有一个小优化吧,建一个n+1点,k++,建他的费用为0,w、d都给inf。那么无论如何想要最大都会有这个点
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 20010
#define inf 0x3f3f3f3f
int n,m,d[N],c[N],s[N],w[N],L[N],R[N],h[N],dp[N];
struct node{int x,f;}tree[N<<2];
struct node1{int to,next;}e[N];
void pushup(int v){tree[v].x=min(tree[v<<1].x,tree[v<<1|1].x);}
void pushdown(int v){
if(!tree[v].f) return;
tree[v<<1].f+=tree[v].f;tree[v<<1|1].f+=tree[v].f;
tree[v<<1].x+=tree[v].f;tree[v<<1|1].x+=tree[v].f;
tree[v].f=0;
}
void build(int v,int l,int r){
tree[v].f=0;
if(l==r){
tree[v].x=dp[l];
return;
}int mid=l+r>>1;
build(v<<1,l,mid);build(v<<1|1,mid+1,r);
pushup(v);
}
void add(int v,int l,int r,int x,int y,int z){
if(x>y) return;
if(x<=l && r<=y){
tree[v].x+=z;tree[v].f+=z;
return;
}int mid=l+r>>1;pushdown(v);
if(x<=mid) add(v<<1,l,mid,x,y,z);
if(mid<y) add(v<<1|1,mid+1,r,x,y,z);
pushup(v);
}
int query(int v,int l,int r,int x,int y){
if(x>y) return 0;
if(x<=l && r<=y) return tree[v].x;
int mid=l+r>>1,s=inf;pushdown(v);
if(x<=mid) s=min(query(v<<1,l,mid,x,y),s);
if(mid<y) s=min(query(v<<1|1,mid+1,r,x,y),s);
return s;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=2;i<=n;i++) scanf("%d",&d[i]);
for(int i=1;i<=n;i++) scanf("%d",&c[i]);
for(int i=1;i<=n;i++) scanf("%d",&s[i]);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
d[++n]=inf;c[n]=0;w[n]=inf;m++;
for(int i=1;i<=n;i++){
L[i]=lower_bound(d+1,d+n+1,d[i]-s[i])-d;
R[i]=upper_bound(d+1,d+n+1,d[i]+s[i])-d-1;
e[i].to=i;e[i].next=h[R[i]];h[R[i]]=i;
}
int tmp=0;for(int i=1;i<=n;i++){
dp[i]=tmp+c[i];
for(int j=h[i];j;j=e[j].next) tmp+=w[e[j].to];
}int ans=dp[n];
for(int j=2;j<=m;j++){
build(1,1,n);memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
dp[i]=query(1,1,n,1,i-1)+c[i];
for(int k=h[i];k;k=e[k].next) add(1,1,n,1,L[e[k].to]-1,w[e[k].to]);
}
ans=min(dp[n],ans);
}
printf("%d\n",ans);
return 0;
}