zoukankan      html  css  js  c++  java
  • 【洛谷P2605】基站选址

    题目

    题目链接:https://www.luogu.com.cn/problem/P2605
    (N) 个村庄坐落在一条直线上,第 (i(i>1)) 个村庄距离第 (1) 个村庄的距离为 (D_i)。需要在这些村庄中建立不超过 (K) 个通讯基站,在第 (i) 个村庄建立基站的费用为 (C_i)。如果在距离第 (i) 个村庄不超过 (S_i) 的范围内建立了一个通讯基站,那么就村庄被基站覆盖了。如果第 (i) 个村庄没有被覆盖,则需要向他们补偿,费用为 (W_i)。现在的问题是,选择基站的位置,使得总费用最小。
    (Nleq 20000,Kleq 100)

    思路

    (f[i][j]) 表示在前 (i) 个村庄,安装了 (j) 个通讯基站的最小代价。
    考虑枚举上一次选择安装基站的位置 (k),有转移

    [f[i][j]=min_{k<i}left(f[k][j-1]+sum^{i-1}_{l=k+1}[d_l+s_l<d_i] imes [d_l-s_l>d_k] imes 1 ight) ]

    直接转移是 (O(n^2k)) 的,看到区间最小值,考虑维护 (k) 棵线段树优化转移。
    对于一个位置 (k(k<i)),如果满足 (d_k+s_k<d_i),那么对于 (d_k-s_k>d_j) 的所有 (j),从 (f[j][l-1]) 转移到 (f[i][l]) 的时候都会算上 (w_k) 的贡献。所以我们可以按照 (d_i-s_i) 从小到大排序,当我们枚举到 (i) 时,维护一个指针 (j),把所有 (d_j+s_j<d_i)(j),在线段树上区间 ([1,d_j-s_j-1]) 加上 (w_j) 即可。
    时间复杂度 (O(nklog n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=20010,M=101,Inf=2e9;
    int n,m,ans,sum,d[N],c[N],s[N],w[N],id[N],L[N],f[N][M];
    
    bool cmp1(int x,int y)
    {
    	return d[x]+s[x]<d[y]+s[y];
    }
    
    bool cmp2(int x,int y)
    {
    	return d[x]-s[x]>d[y]-s[y];
    }
    
    struct SegTree
    {
    	int lazy[N*4],minn[N*4];
    	
    	void pushdown(int x)
    	{
    		if (lazy[x])
    		{
    			minn[x*2]+=lazy[x]; minn[x*2+1]+=lazy[x];
    			lazy[x*2]+=lazy[x]; lazy[x*2+1]+=lazy[x];
    			lazy[x]=0;
    		}
    	}
    	
    	void update(int x,int l,int r,int ql,int qr,int v)
    	{
    		if (ql>qr) return;
    		if (ql<=l && qr>=r)
    			return (void)(lazy[x]+=v,minn[x]+=v);
    		pushdown(x);
    		int mid=(l+r)>>1;
    		if (ql<=mid) update(x*2,l,mid,ql,qr,v);
    		if (qr>mid) update(x*2+1,mid+1,r,ql,qr,v);
    		minn[x]=min(minn[x*2],minn[x*2+1]);
    	}
    	
    	int query(int x,int l,int r,int ql,int qr)
    	{
    		if (ql>qr) return 0;
    		if (ql<=l && qr>=r) return minn[x];
    		pushdown(x);
    		int mid=(l+r)>>1,res=Inf;
    		if (ql<=mid) res=min(res,query(x*2,l,mid,ql,qr));
    		if (qr>mid) res=min(res,query(x*2+1,mid+1,r,ql,qr));
    		return res;
    	}
    }seg[M];
    
    int main()
    {
    	cerr<<(sizeof(seg)+sizeof(f))/1024/1024<<"
    ";
    	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]);
    	for (int i=1;i<=n;i++)
    	{
    		id[i]=i; ans+=w[i];
    		L[i]=lower_bound(d+1,d+1+n,d[i]-s[i])-d-1;
    	}
    	sort(id+1,id+1+n,cmp1);
    	for (int i=1,k=1;i<=n;i++)
    	{
    		for (;k<=n && d[id[k]]+s[id[k]]<d[i];k++)
    		{
    			sum+=w[id[k]];
    			for (int j=0;j<=m;j++)
    				seg[j].update(1,1,n,1,L[id[k]],w[id[k]]);
    		}
    		f[i][1]=c[i]+sum;
    		seg[1].update(1,1,n,i,i,f[i][1]);
    		for (int j=2;j<=m;j++)
    		{
    			f[i][j]=seg[j-1].query(1,1,n,1,i-1)+c[i];
    			seg[j].update(1,1,n,i,i,f[i][j]);
    		}
    	}
    	sum=0;
    	sort(id+1,id+1+n,cmp2);
    	for (int i=n;i>=1;i--) w[i]+=w[i+1];
    	for (int i=n,k=1;i>=1;i--)
    	{
    		for (;k<=n && d[id[k]]-s[id[k]]>d[i];k++)
    			sum+=w[id[k]]-w[id[k]+1];
    		for (int j=1;j<=m;j++)
    			ans=min(ans,f[i][j]+sum);
    	}
    	cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    docker 安装mysql
    Java web项目搭建系列之二 Jetty下运行项目
    Java web项目搭建系列之一 Eclipse中新建Maven项目
    Maven 添加其他Maven组件配置问题
    C# 中定义扩展方法
    Oracle 函数
    【Webservice】2 counts of IllegalAnnotationExceptions Two classes have the same XML type name
    Linux精简版系统安装网络配置问题解决
    Rsync 故障排查整理
    Failed to set session cookie. Maybe you are using HTTP instead of HTTPS to access phpMyAdmin.
  • 原文地址:https://www.cnblogs.com/stoorz/p/15114151.html
Copyright © 2011-2022 走看看