RiverSheepSHEEP

P2605 [ZJOI2010]基站选址

奔跑的心634·2022-03-16 19:14·31 次阅读

P2605 [ZJOI2010]基站选址

Solution#

一道比较简单线段树优化DP,但它是黑色的!!!
一个显然的DP,设fi,j表示选到第i个(i必选),建了j个基站。

fi,j=fk,j1+Swk,i+Ci

Swi,j表示ij中没被覆盖的村庄的补偿总费用
这样DPO(n2)
发现对于一个村庄x,如果转移的j不在区间[xSx,x+Sx]内就会加Wx,那么就可以用线段树维护DP值,对区间[1,xSx1]的数加上Wx即可。
最后的答案在随便处理一下即可。

Code#

Copy
#include<cstdio> #include<algorithm> using namespace std; const int N = 2e4 + 5,inf = 1e9; int n,m,d[N],c[N],w[N],f[N << 2],tag[N << 2],g[N][105]; struct nd{int l,r,id;}a[N]; bool cmp(nd x,nd y){return x.r < y.r;} void build(int l,int r,int k,int x) { tag[k] = 0; if (l == r) return f[k] = g[l][x],void(); int mid = l + r >> 1; build(l,mid,k << 1,x),build(mid + 1,r,k << 1 | 1,x); f[k] = min(f[k << 1],f[k << 1 | 1]); } void pushdown(int k) { if (!tag[k]) return; tag[k << 1] += tag[k],tag[k << 1 | 1] += tag[k]; f[k << 1] += tag[k],f[k << 1 | 1] += tag[k],tag[k] = 0; } void update(int l,int r,int k,int L,int R,int v) { if (L > R || l > R || r < L || !v) return; if (L <= l && r <= R) return f[k] += v,tag[k] += v,void(); pushdown(k); int mid = l + r >> 1; if (L <= mid) update(l,mid,k << 1,L,R,v); if (R > mid) update(mid + 1,r,k << 1 | 1,L,R,v); f[k] = min(f[k << 1],f[k << 1 | 1]); } int query(int l,int r,int k,int L,int R) { if (L <= l && r <= R) return f[k]; pushdown(k); int mid = l + r >> 1,tmp = inf; if (L <= mid) tmp = query(l,mid,k << 1,L,R); if (R > mid) tmp = min(tmp,query(mid + 1,r,k << 1 | 1,L,R)); return tmp; } 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,s; i <= n; i++) { scanf("%d",&s),a[i] = nd{d[i] - s,d[i] + s,i}; int l = 1,r = n,res = 1; while (l <= r) { int mid = l + r >> 1; if (d[mid] >= a[i].l) res = mid,r = mid - 1; else l = mid + 1; }a[i].l = res,l = 1,r = n,res = n; while (l <= r) { int mid = l + r >> 1; if (d[mid] <= a[i].r) res = mid,l = mid + 1; else r = mid - 1; }a[i].r = res; } for (int i = 1; i <= n; i++) scanf("%d",&w[i]); n++,a[n] = nd{n,n,n}; sort(a + 1,a + 1 + n,cmp); int ans = inf; for (int i = 0; i <= n; i++) for (int j = 0; j <= m; j++) g[i][j] = inf; g[0][0] = 0; for (int j = 1; j <= m + 1; j++) { build(0,n,1,j - 1); for (int i = 1,k = 1; i <= n; i++) { while (k <= n && a[k].r < i) update(0,n,1,0,a[k].l - 1,w[a[k].id]),k++; g[i][j] = query(0,n,1,0,i - 1) + c[i]; } } for (int i = 1; i <= m + 1; i++) ans = min(ans,g[n][i]); printf("%d\n",ans); }
posted @   RiverSheep  阅读(31)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示
目录