zoukankan      html  css  js  c++  java
  • [ZJOI2010]基站选址

    简单题
    (f_{i,j})表示选择了(i)个关键点,最后一个关键点选择的位置是(j)([1,j])的最小代价。
    显然(f_{i,j}=min(f_{i-1,k}+w(k+1,j)),k<j)(w(i,j))为区间(i,j)左边/右边放置基站的代价函数。
    由于我们知道当前这一段左/右最近的点,所以代价可以在(O(n))的时间内扫描计算。
    时间复杂度为(O(n^3k))
    考虑优化,把点分成2类。
    如果当前点(x)距离(ileq s_x),则是(1)类点,费用为(0)
    否则是(2)类点,当左边放置基站位置离(jleq s_x),费用为(0),否则费用为(W_j)
    (k)往左移动时,每个点的类型不会变化。
    而二类点能够产生代价贡献的(k)是区间,可以通过二分预处理。
    可以差分维护代价。
    时间复杂度变为(O(n^2k))
    考虑继续优化,对(f_{i-1})建立一颗线段树。
    (j)向右移动时,一些一类点可能变为二类点。
    预处理出每个点变成二类点时(j)的位置。
    这时这些点就会对区间产生贡献。
    可以使用区间加法/(min)维护。
    这需要我们求出一个点(i)左边/右边第一个距离(>s_i)的位置,可以二分。
    时间复杂度变为(O(knlog_2n))

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    using namespace std;
    #define N 100010
    int n,k,f[120][N],tg[N],mn[N],d[N],c[N],s[N],w[N],a[N],l[N],r[N];
    struct no{
    	int l,r,v;
    };
    vector<no>g[N];
    void bd(int o,int l,int r){
    	if(l==r){
    		mn[o]=a[l];
    		return;
    	}
    	int md=(l+r)/2;
    	bd(o*2,l,md);
    	bd(o*2+1,md+1,r);
    	mn[o]=min(mn[o*2],mn[o*2+1]);
    }
    void pd(int o){
    	if(tg[o]){
    		tg[o*2]+=tg[o];
    		tg[o*2+1]+=tg[o];
    		mn[o*2]+=tg[o];
    		mn[o*2+1]+=tg[o];
    		tg[o]=0;
    	}
    }
    void ad(int o,int l,int r,int x,int y,int z){
    	if(r<x||y<l)
    		return;
    	if(x<=l&&r<=y){
    		tg[o]+=z;
    		mn[o]+=z;
    		return;
    	}
    	pd(o);
    	int md=(l+r)/2;
    	ad(o*2,l,md,x,y,z);
    	ad(o*2+1,md+1,r,x,y,z);
    	mn[o]=min(mn[o*2],mn[o*2+1]);
    }
    int qu(int o,int l,int r,int x,int y){
    	if(r<x||y<l)
    		return 1e18;
    	if(x<=l&&r<=y)
    		return mn[o];
    	pd(o);
    	int md=(l+r)/2;
    	return min(qu(o*2,l,md,x,y),qu(o*2+1,md+1,r,x,y));
    }
    int e1(int p,int s){
    	int l=p,r=n+1,ans=n+1;
    	while(l<=r){
    		int md=(l+r)/2;
    		if(d[md]-d[p]>s){
    			ans=md;
    			r=md-1; 
    		}
    		else
    			l=md+1;
    	}
    	return ans;
    }
    int e2(int p,int s){
    	int l=0,r=p,ans=0;
    	while(l<=r){
    		int md=(l+r)/2;
    		if(d[p]-d[md]>s){
    			ans=md;
    			l=md+1;
    		}
    		else
    			r=md-1;
    	}
    	return ans;
    }
    signed main(){
    	scanf("%lld%lld",&n,&k);
    	for(int i=2;i<=n;i++)
    		scanf("%lld",&d[i]);
    	d[0]=-1e16;
    	d[n+1]=1e16;
    	for(int i=1;i<=n;i++)
    		scanf("%lld",&c[i]);
    	for(int i=1;i<=n;i++)
    		scanf("%lld",&s[i]);
    	for(int i=1;i<=n;i++)
    		scanf("%lld",&w[i]);
    	for(int i=0;i<=n;i++){
    		r[i]=e1(i,s[i]);
    		l[i]=e2(i,s[i]);
    		g[r[i]].push_back((no){0,l[i],w[i]});
    	}
    	memset(f,32,sizeof(f));
    	f[0][0]=0;
    	for(int i=0;i<=k;i++){
    		memset(tg,0,sizeof(tg));
    		memset(mn,0,sizeof(mn));
    		for(int j=0;j<=n+1;j++)
    			a[j]=f[i][j];
    		bd(1,0,n+1);
    		for(int j=1;j<=n+1;j++){
    			for(int l=0;l<g[j].size();l++){
    				no x=g[j][l];
    				ad(1,0,n+1,x.l,x.r,x.v);
    			}
    			f[i+1][j]=qu(1,0,n+1,0,j-1)+c[j];
    		}
    	}
    	int ans=1e17;
    	for(int i=0;i<=k+2;i++)
    		ans=min(ans,f[i][n+1]);
    	printf("%lld",ans);
    } 
    
  • 相关阅读:
    JQuery.Gantt(甘特图)开发
    文件上传利器SWFUpload入门简易教程
    ES6:JavaScript 新特性
    记一次关于垃圾回收app的推广成功案例
    c#游戏之路-wpf版本开发
    C#游戏之路-winform,wpf,directx,opengl的了解
    Python3 引号
    while循环练习
    用jquery实现瀑布流(方式1-固定宽度和列数,按顺序添加图片)
    jquery实现图片轮播淡入淡出效果
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/14590833.html
Copyright © 2011-2022 走看看