题解:Dp+线段树维护所有决策
f[i][j]表示第j个基站建在第i个位置,i之前的村庄与建基站的总费用的最小值
以j为阶段
枚举i,维护所有决策f[x][j-1];
当一个村庄q不能被i覆盖了,那么在1~p之间建立基站的决策费用要+c
p为q左边第一个不能覆盖q的村庄
复杂度O( nklogn);
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int maxn=20009; const int inf=1000000000; int n,m; int ans=inf; int f[maxn][109]; int d[maxn]; int c[maxn]; int w[maxn]; int s[maxn]; int Bl[maxn],Br[maxn]; vector<int>Tr[maxn],Tl[maxn]; struct SegmentTree{ int l,r,tag,mn; }tree[maxn<<2]; inline void pushup(int now){ tree[now].mn=min(tree[now<<1].mn,tree[now<<1|1].mn); } inline void pushdown(int now){ if(tree[now].tag){ tree[now<<1].tag+=tree[now].tag; tree[now<<1|1].tag+=tree[now].tag; tree[now<<1].mn+=tree[now].tag; tree[now<<1|1].mn+=tree[now].tag; tree[now].tag=0; } } void BuildTree(int now,int l,int r,int p){ tree[now].l=l;tree[now].r=r;tree[now].tag=0; if(l==r){ tree[now].mn=f[l][p]; return; } int mid=(l+r)>>1; BuildTree(now<<1,l,mid,p); BuildTree(now<<1|1,mid+1,r,p); pushup(now); } void Updatasec(int now,int ll,int rr,int x){ if(ll>rr)return; if(tree[now].l>=ll&&tree[now].r<=rr){ tree[now].tag+=x;tree[now].mn+=x;return; } pushdown(now); int mid=(tree[now].l+tree[now].r)>>1; if(ll<=mid)Updatasec(now<<1,ll,rr,x); if(rr>mid)Updatasec(now<<1|1,ll,rr,x); pushup(now); } int Querymin(int now,int ll,int rr){ if(tree[now].l>=ll&&tree[now].r<=rr){ return tree[now].mn; } pushdown(now); int mid=(tree[now].l+tree[now].r)>>1; int ret=inf; if(ll<=mid)ret=min(ret,Querymin(now<<1,ll,rr)); if(rr>mid)ret=min(ret,Querymin(now<<1|1,ll,rr)); return ret; } int main(){ scanf("%d%d",&n,&m); d[1]=0; 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]); for(int i=1;i<=n;++i){ int p,tmp; tmp=d[i]+s[i]; p=lower_bound(d+1,d+1+n,tmp)-d; if(tmp<=d[n]){ if(d[p]!=tmp)--p; Tr[p].push_back(i); Br[i]=p; }else{ Br[i]=-1; } tmp=d[i]-s[i]; p=lower_bound(d+1,d+1+n,tmp)-d; if(tmp>=0){ Tl[p].push_back(i); Bl[i]=p; }else{ Bl[i]=-1; } } // for(int i=1;i<=n;++i){ // cout<<Bl[i]<<‘ ‘<<Br[i]<<endl; // } for(int tmp=0,i=1;i<=n;++i){ // cout<<"ASD"<<‘ ‘<<i<<‘ ‘<<tmp<<endl; f[i][1]=tmp+c[i]; for(int j=0;j<Tr[i].size();++j){ int x=Tr[i][j]; tmp+=w[x]; // cout<<"eaint "<<tmp<<endl; } } for(int j=2;j<=m;++j){ BuildTree(1,1,n,j-1); for(int i=1;i<=j-1;++i)f[i][j]=inf; for(int i=j;i<=n;++i){ f[i][j]=Querymin(1,1,i-1)+c[i]; for(int k=0;k<Tr[i].size();++k){ int x=Tr[i][k]; if(Bl[x]>1)Updatasec(1,1,Bl[x]-1,w[x]); } } } for(int tmp=0,i=n;i>=1;--i){ for(int j=1;j<=m;++j){ ans=min(ans,f[i][j]+tmp); } for(int j=0;j<Tl[i].size();++j){ int x=Tl[i][j]; tmp+=w[x]; } } // for(int j=1;j<=m;++j){ // for(int i=1;i<=n;++i){ // cout<<f[i][j]<<‘ ‘; // } // cout<<endl; // } cout<<ans<<endl; return 0; }