正解:线段树优化$dp$
解题报告:
难受阿,,,本来想做考试题的,我还造了个精妙无比的题面,然后今天讲$dp$的时候被讲到了$kk$
先考虑暴力$dp$?就设$f_{i,j}$表示选的第$j$个基站是$i$的最小费用,就有$f_{i,j}=min(f_{k,j}+cost(k,i))+c_i$,这个$cost$就$[k+1,i-1]$之间所有基站的补偿之和.
发现这个$cost$并不好求?于是逆向思考,每次在决策完选$x$转移完之后就会进入不选$x$的阶段嘛(因为是,$j$在外层循环$i$在内层,也就每次只会选一个基站,所以决策完第$j$个选$x$后就会决策第$j$个选$x$之后的基站,那第$x$个基站就不会被选了$QwQ$),那就把$[1,x]$范围内所有因为不选$x$而导致代价增加的加上
于是先预处理一个$st_{i}$和一个$ed_{i}$数组,表示能让$i$被覆盖的基站的编号范围,然后每次把所有$ed_{i}=x$的点找出来.但是发现当上一次选的点在$[st_{i},ed_{i}-1]$范围内的时候就依然没有关系,所以就只要$f_{[1,st[i]-1],j}+=w_i$
现在就变成了区间加区间查询最小值,线段树维护就好,$over$
#include<bits/stdc++.h> using namespace std; #define il inline #define gc getchar() #define t(i) edge[i].to #define ri register int #define rc register char #define rb register bool #define rp(i,x,y) for(ri i=x;i<=y;++i) #define my(i,x,y) for(ri i=x;i>=y;--i) #define e(i,x) for(ri i=head[x];i;i=edge[i].nxt) #define lb(x) lower_bound(d+1,d+1+n,x)-d const int N=20000+10,inf=0x3f3f3f3f; int n,K,d[N],c[N],s[N],w[N],st[N],ed[N],tr[N<<2],tag[N<<2],ed_cnt,head[N],f[N],as; struct edg{int to,nxt;}edge[N]; il int read() { rc ch=gc;ri x=0;rb y=1; while(ch!='-' && (ch>'9' || ch<'0'))ch=gc; if(ch=='-')ch=gc,y=0; while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc; return y?x:-x; } il void ad(ri x,ri y){edge[++ed_cnt]=(edg){x,head[y]};head[y]=ed_cnt;} void build(ri nw,ri l,ri r) { tag[nw]=0;if(l==r)return void(tr[nw]=f[l]); ri mid=(l+r)>>1;build(nw<<1,l,mid);build(nw<<1|1,mid+1,r); tr[nw]=min(tr[nw<<1],tr[nw<<1|1]); } il void pushdown(ri nw) { if(!tag[nw])return; tag[nw<<1]+=tag[nw];tag[nw<<1|1]+=tag[nw];tr[nw<<1]+=tag[nw];tr[nw<<1|1]+=tag[nw];tag[nw]=0; } void add(ri nw,ri l,ri r,ri to_l,ri to_r,ri dat) { if(to_l<=l && r<=to_r){tr[nw]+=dat;tag[nw]+=dat;return;}//return void(tr[nw]+=dat,tag[nw]+=dat); pushdown(nw);ri mid=(l+r)>>1; if(mid>=to_l)add(nw<<1,l,mid,to_l,to_r,dat);if(mid<to_r)add(nw<<1|1,mid+1,r,to_l,to_r,dat); tr[nw]=min(tr[nw<<1],tr[nw<<1|1]); } int query(ri nw,ri l,ri r,ri to_l,ri to_r) { // printf("nw=%d l=%d r=%d to_l=%d to_r=%d\n",nw,l,r,to_l,to_r); if(to_l<=l && r<=to_r)return tr[nw]; pushdown(nw);ri mid=(l+r)>>1,ret=inf; if(mid>=to_l)ret=query(nw<<1,l,mid,to_l,to_r);if(mid<to_r)ret=min(ret,query(nw<<1|1,mid+1,r,to_l,to_r)); // printf("[%d,%d]:%d\n") return ret; } int main() { // freopen("2605.in","r",stdin);//freopen("2605.out","w",stdout); n=read();K=read()+1;rp(i,2,n)d[i]=read();rp(i,1,n)c[i]=read();rp(i,1,n)s[i]=read();rp(i,1,n)w[i]=read();++n;d[n]=w[n]=inf; rp(i,1,n){st[i]=lb(d[i]-s[i]);ed[i]=lb(d[i]+s[i]);if(d[ed[i]]>d[i]+s[i])--ed[i];ad(i,ed[i]);} ri ret=0;rp(i,1,n){f[i]=ret+c[i];e(j,i)ret+=w[t(j)];}as=f[n]; rp(i,2,K) { build(1,1,n); rp(j,1,n) { f[j]=(j>i-1?query(1,1,n,i-1,j-1):0)+c[j];//printf("f[%d]=%d=%d+%d\n",j,f[j],j>i-1?query(1,1,n,1,j-1):0,c[j]); e(k,j)if(st[t(k)]>1)add(1,1,n,1,st[t(k)]-1,w[t(k)]); } as=min(as,f[n]); } printf("%d\n",as); return 0; }View Code