四川企业品牌网站建设,软件下载网站怎么做,石家庄做网络推广的网站,做美食推广的网站正题
luogu 2605 金牌导航 数据结构优化DP-2 题目大意
有若干个村庄在一条直线上#xff0c;距离第一个村庄did_idi#xff0c;在该村庄建立基站要花费cic_ici#xff0c;如果在离该村不大于sis_isi的范围内有一个基站#xff0c;那么该村会被信号覆盖#xff0c;…正题
luogu 2605 金牌导航 数据结构优化DP-2 题目大意
有若干个村庄在一条直线上距离第一个村庄did_idi在该村庄建立基站要花费cic_ici如果在离该村不大于sis_isi的范围内有一个基站那么该村会被信号覆盖如果一个村庄没有被信号覆盖那么有wiw_iwi的代价
现在最多建k个基站问你最小代价 解题思路
设fi,jf_{i,j}fi,j为在第i个村庄建建第j个基站的费用
那么有fi,jmink1i−1(fk,j−1costk,i)f_{i,j}min_{k1}^{i-1}(f_{k, j - 1} cost_{k, i})fi,jmink1i−1(fk,j−1costk,i)cost为在k,i建基站中间覆盖不到的村庄的代价
第二维可以在外面枚举而省掉那么有fimink1i−1(fkcostk,i)f_imin_{k1}^{i-1}(f_k cost_{k, i})fimink1i−1(fkcostk,i)
现在考虑计算cost的优化
可以先预处理出sti,edist_i,ed_isti,edi分别为可以遍历到i的点中最左/右的这可以用二分实现
计算完后在edied_iedi建立a数组把i丢进去得到的就是以x(i⩽x)x(i\leqslant x)x(i⩽x)为最后一个可以覆盖到的该点的点就是x可以覆盖i而x1覆盖不到i
当我们计算完fif_ifi时由于后面的点无法遍历到a里面的点所以如果从stk(k∈a)st_k(k\in a)stk(k∈a)前面的点转移到后面那么k点就被覆盖到就要加上wkw_kwk所以对[1, st_k-1]加上wkw_kwk
因为fif_ifi的上一个基站在[1,i-1]内所以在[1,i-1]中找最小值即可
找最小值得这个过程可以用线段树来实现
对于求解答案可以在末尾再加一个点该点winf,dinf,c0,s0winf,dinf,c0,s0winf,dinf,c0,s0然后使建基站的最大数量1然后在该点找答案即可 代码
#includevector
#includecstdio
#includecstring
#includeiostream
#includealgorithm
#define ll long long
#define N 20021
using namespace std;
int n, m, ans, d[N], c[N], s[N], w[N], f[N], st[N], ed[N];
vectorinta[N];
struct Tree
{int s[N2], lazy[N2];#define ls x*2#define rs x*21void up(int x){s[x] min(s[ls], s[rs]);return;}void down(int x){if (lazy[x]){lazy[ls] lazy[x];lazy[rs] lazy[x];s[ls] lazy[x];s[rs] lazy[x];lazy[x] 0;}return;}void build(int x, int l, int r){lazy[x] 0;if (l r){s[x] f[l];return;}int mid l r 1;build(ls, l, mid);build(rs, mid 1, r);up(x);return;}void change(int x, int L, int R, int l, int r, int y){if (l r) return;if (L l R r){lazy[x] y;s[x] y;return;}int mid L R 1;down(x);if (r mid) change(ls, L, mid, l, r, y);else if(l mid) change(rs, mid 1, R, l, r, y);else change(ls, L, mid, l, mid, y), change(rs, mid 1, R, mid 1, r, y);up(x);return;}int ask(int x, int L, int R, int l, int r){if (l r) return 0;if (L l R r) return s[x];int mid L R 1;down(x);if (r mid) return ask(ls, L, mid, l, r);else if (l mid) return ask(rs, mid 1, R, l, r);else return min(ask(ls, L, mid, l, mid), ask(rs, mid 1, R, mid 1, r));}
}T;
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]);n;m;d[n] w[n] 2000000001;for (int i 1; i n; i){st[i] lower_bound(d 1, d 1 n, d[i] - s[i]) - d;//计算st,eded[i] upper_bound(d 1, d 1 n, d[i] s[i]) - d - 1;a[ed[i]].push_back(i);}int g 0;for (int i 1; i n; i)//前面没有基站{f[i] g c[i];for (int j 0; j a[i].size(); j)g w[a[i][j]];}ans f[n];for (int k 1; k m; k){T.build(1, 1, n);for (int i 1; i n; i){f[i] T.ask(1, 1, n, 1, i - 1) c[i];for (int j 0; j a[i].size(); j)T.change(1, 1, n, 1, st[a[i][j]] - 1, w[a[i][j]]);//后面的点遍历不到}ans min(ans, f[n]);}printf(%d, ans);return 0;
}