Luogu P2605 [ZJOI2010]基站选址

题目
首先设\(f_{i,j}\)表示在第\(i\)个村庄修了\(j\)个基站的答案。
那么\(f_{i,j}=c_i+\min\limits_{k\in[j-1,i)}(f_{k,j-1}+cost_{k,i})\)。
其中\(cost_{k,i}\)表示只在\(k,i\)修基站的情况下\((k,i)\)中未被覆盖的村庄的\(w\)之和。
我们发现\(j\)可以滚掉,把枚举\(j\)放到外面一层来,就有\(f_i=c_i+\min\limits_{k\in[j-1,i)}(f_k+cost_{k,i})\)。
这东西直接算肯定没法做,我们分析一下每个部分本质上是什么。
首先我们观察\(f_i\)的计算式,\(c_i\)是完全不变的,可以无视掉。
而\(f_k+cost_{k,i}\)这个东西,在固定一个\(i\)时它是一个与\(k\)有关的变量。
那么一个比较自然的想法就是,每次将\(i-1\)扩展至\(i\)时,我们先求出\(f_i\)(在\(i\)位置修一个基站),然后对\(cost\)进行更新(在\(i\)位置不修基站)。
对于一个村庄\(i\),我们先预处理\(st_i,ed_i\),如果在\([st_i,ed_i]\)内没有哪个村庄修了基站的话这个村庄\(i\)就需要被赔偿。
因为\(i\)位置不修基站,所以我们需要处理所有\(ed_p=i\)的\(p\)村庄对\(cost\)的影响。
\(p\)村庄需要被赔偿等价于上一个基站在\([1,st_p-1]\),也就是从\(f_1\sim f_{st_p-1}\)转移过来的需要加上\(w_p\),即把\(cost_{1,i}\sim cost_{st_p-1,i}\)加上\(w_p\)。
那么我们用线段树维护\(f_k+cost_{k,i}\),支持区间加和区间求最小值即可。

#include<cstdio>
#include<cctype>
#include<vector>
#include<algorithm>
#define pb push_back
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)>>1)
const int N=20007,inf=0x3f3f3f3f;
using namespace std;
int read(){int x=0,c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))x=x*10+c-48,c=getchar();return x;}
int max(int a,int b){return a>b? a:b;}
int min(int a,int b){return a<b? a:b;}
int d[N],c[N],s[N],w[N],f[N],st[N],ed[N],val[N<<2],tag[N<<2];
vector<int>edp[N];
void pushup(int p){val[p]=min(val[ls],val[rs]);}
void add(int p,int v){val[p]+=v,tag[p]+=v;}
void pushdown(int p){add(ls,tag[p]),add(rs,tag[p]),tag[p]=0;}
void build(int p,int l,int r)
{
    tag[p]=0;
    if(l==r) return (void)(val[p]=f[l]);
    build(ls,l,mid),build(rs,mid+1,r),pushup(p);
}
void update(int p,int l,int r,int L,int R,int v)
{
    if(L<=l&&r<=R) return (void)(tag[p]+=v,val[p]+=v);
    if(tag[p]) pushdown(p);
    if(L<=mid) update(ls,l,mid,L,R,v);
    if(R>mid) update(rs,mid+1,r,L,R,v);
    pushup(p);
}
int query(int p,int l,int r,int L,int R)
{
    if(L<=l&&r<=R) return val[p];
    if(tag[p]) pushdown(p);
    return min((L<=mid? query(ls,l,mid,L,R):inf),(R>mid? query(rs,mid+1,r,L,R):inf));
}
int main()
{
    int n=read(),k=read()+1,i,j,sum,ans;
    for(i=2;i<=n;++i) d[i]=read();
    for(i=1;i<=n;++i) c[i]=read();
    for(i=1;i<=n;++i) s[i]=read();
    for(i=1;i<=n;++i) w[i]=read();
    ++n,d[n]=w[n]=inf;
    for(i=1;i<=n;++i) st[i]=lower_bound(d+1,d+n+1,d[i]-s[i])-d,ed[i]=upper_bound(d+1,d+n+1,d[i]+s[i])-d-1,edp[ed[i]].pb(i);
    for(i=1,sum=0;i<=n;++i)
    {
    f[i]=sum+c[i];
    for(int p:edp[i]) sum+=w[p];
    }
    ans=f[n];
    for(i=2;i<=k;++i)
    {
    build(1,1,n);
    for(j=1;j<=n;++j)
    {
        f[j]=(j>i-1? query(1,1,n,i-1,j-1):0)+c[j];
        for(int p:edp[j]) if(st[p]>1) update(1,1,n,1,st[p]-1,w[p]);
    }
    ans=min(ans,f[n]);
    }
    printf("%d",ans);
}

原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/11765391.html

时间: 2024-10-08 00:40:56

Luogu P2605 [ZJOI2010]基站选址的相关文章

P2605 [ZJOI2010]基站选址

题目描述 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄不超过Si的范围内建立了一个通讯基站,那么就村庄被基站覆盖了.如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi.现在的问题是,选择基站的位置,使得总费用最小. 输入输出格式 输入格式: 输入文件的第一行包含两个整数N,K,含义如上所述. 第二行包含N-1个整数,分别表示D2,D3,…,DN ,这N-1个数是递增的

[ZJOI2010]基站选址

题目描述 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄不超过Si的范围内建立了一个通讯基站,那么就村庄被基站覆盖了.如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi.现在的问题是,选择基站的位置,使得总费用最小. 输入输出格式 输入格式: 输入文件的第一行包含两个整数N,K,含义如上所述. 第二行包含N-1个整数,分别表示D2,D3,-,DN ,这N-1个数是递增的

[ZJOI2010]基站选址(线段树优化dp)

坑待填. \(Code\ Below:\) #include <bits/stdc++.h> #define lson (rt<<1) #define rson (rt<<1|1) using namespace std; const int maxn=20000+10; const int inf=0x3f3f3f3f; int n,k,d[maxn],c[maxn],s[maxn],w[maxn],f[maxn],st[maxn],ed[maxn],sum[maxn

【BZOJ1835】[ZJOI2010]base 基站选址 线段树+DP

[BZOJ1835][ZJOI2010]base 基站选址 Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄不超过Si的范围内建立了一个通讯基站,那么就成它被覆盖了.如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi.现在的问题是,选择基站的位置,使得总费用最小. 输入数据 (base.in) 输入文件的第一行包含两个整数N,K,含义如上所述. 第

hiho 编程之美2015资格赛(基站选址-绝对值方程分段)[无数据]

题目3 : 基站选址 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 需要在一个N × M的网格中建立一个通讯基站,通讯基站仅必须建立在格点上. 网格中有A个用户,每个用户的通讯代价是用户到基站欧几里得距离的平方. 网格中还有B个通讯公司,维护基站的代价是基站到最近的一个通讯公司的路程(路程定义为曼哈顿距离). 在网格中建立基站的总代价是用户通讯代价的总和加上维护基站的代价,最小总代价. 输入 第一行为一个整数T,表示数据组数. 每组数据第一行为四个整数:N, M,

编程之美2015资格赛:基站选址

题目3 : 基站选址 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 需要在一个N × M的网格中建立一个通讯基站,通讯基站仅必须建立在格点上. 网格中有A个用户,每个用户的通讯代价是用户到基站欧几里得距离的平方. 网格中还有B个通讯公司,维护基站的代价是基站到最近的一个通讯公司的路程(路程定义为曼哈顿距离). 在网格中建立基站的总代价是用户通讯代价的总和加上维护基站的代价,最小总代价. 输入 第一行为一个整数T,表示数据组数. 每组数据第一行为四个整数:N, M,

BZOJ 1835 基站选址(线段树优化DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1835 题意:有N个村庄坐落在一条直线上,第 i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村 庄不超过Si的范围内建立了一个通讯基站,那么就成它被覆盖了.如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi.现在的问题是,选择基站的位 置,使得总费用最小. 思路: 另外,程序中的n=n+1,m=

编程之美2015 资格赛 hihocoder 题目3 : 基站选址

题意:给一个网格大小,在其中找一个基站,使得到每个用户之间的距离的平方(欧几里得距离的平方),和到其中任一个通讯的距离(曼哈顿距离)的总距离(代价)最小.其实就是到每个用户的距离最小的基础上,到通讯公司也要尽可能近,距离也就是代价. 思路:一开始觉得需要每个点都尝试,计算代价,再比较代价,找出基站最佳位置.但是,这样还叫算法?不是比穷举更快的算法都不叫算法!那么得想办法减少搜索的点,想到基站不可能建立在一个其某一个方向上完全没有用户或者通讯公司的地方,比如用户和通讯公司都在x坐标10以上,而我们

Luogu P2570 [ZJOI2010]贪吃的老鼠

Luogu P2570 [ZJOI2010]贪吃的老鼠 题目描述 奶酪店里最近出现了\(m\)只老鼠!它们的目标就是把生产出来的所有奶酪都吃掉.奶酪店中一天会生产\(n\)块奶酪,其中第\(i\)块的大小为\(pi\),会在第\(ri\)秒被生产出来,并且必须在第\(di\)秒之前将它吃掉.第j只老鼠吃奶酪的速度为\(sj\),因此如果它单独吃完第i快奶酪所需的时间为\(pi/sj\).老鼠们吃奶酪的习惯很独特,具体来说: (1) 在任一时刻,一只老鼠最多可以吃一块奶酪: (2) 在任一时刻,一