• LOJ3282 治疗计划


    治疗计划

    JOI 国有 (N) 个房屋,并从 (1)(N) 编号。这些房屋沿一条直线升序排列。每个房屋有一个居民住在里面。住在编号为 (x) 的房屋里的居民用居民 (x) 表示。

    最近,新冠病毒出现了,并且所有居民都被感染了。为了解决这个问题,有 (M) 个治疗方案被提出。第 (i (1le ile M)) 个治疗方案的花费为 (C_i)。如果执行计划 (i),则会发生以下事件:

    • 在第 (T_i) 天的晚上,如果居民 (x) 满足 (L_ile xle R_i),且他感染了新冠病毒,那么他就会被治愈。

    病毒按如下方式传染相邻的居民:

    • 如果在某天的早晨,居民 (x (1le xle N)) 被病毒感染,那么在同一天的中午,居民 (x-1)(如果 (xge 2))和居民 (x+1)(如果 (xle N-1))就会被感染。

    一个已经被治愈的居民可以再次被病毒感染。

    你是 JOI 国的首相,你需要选取某些方案,使得满足以下条件:

    • 条件:在所有被选中的方案全部执行后,没有居民感染病毒。

    在某一天可以执行多个计划。

    写一个程序,给定房屋和治疗计划的信息,求出能否满足以上条件,若满足,求出最小可能花费。

    对于所有数据,满足 (1le Nle 10^9,1le Mle 10^5)

    题解

    假设有两个区间([L_i,R_i],[L_j,R_j]),其中区间(i)在区间(j)的左侧,那么两个区间能合并当且仅当(R_i-L_j+1geq |T_i-T_j|)

    简单说一下对这个条件的理解:

    • (T_ileq T_j),那么在(j)操作之前病毒从(R_i+1)侵蚀到了(R_i+1-(T_j-T_i))这个位置。所以(j)操作左端点必须至少覆盖到(R_i+1-(T_j-T_i))

    • (T_i>T_j),那么在(i)操作之前病毒从(L_j-1)侵蚀到了(L_j-1+(T_i-T_j))这个位置。所以(i)操作右端点必须至少覆盖到(L_j-1+(T_i-T_j))

    两个条件合并起来就是(R_i-L_j+1geq |T_i-T_j|)

    因为两个区间能否合并只与他们交集的长度和时间差的大小关系有关,所以我们并不需要关注谁先操作谁后操作。

    因为没必要按照时间DP,所以不妨从左到右DP。

    (F(i))表示(T_i)时刻,([1,R_i])的病人都被治愈的最小花费。

    • 初始化所有(L_i=1)(F(i)=C_i)

    • 每次找出最小的(F(i)),尝试转移到其他的(F(j))

    时间复杂度(O(m^2))

    CO int N=2e5+10;
    CO int64 inf=1e18;
    int T[N],L[N],R[N],C[N];
    bool vis[N];int64 F[N];
    
    int main(){
    	int n=read<int>(),m=read<int>();
    	for(int i=1;i<=m;++i){
    		read(T[i]),read(L[i]),read(R[i]),read(C[i]);
    		F[i]=L[i]==1?C[i]:inf;
    	}
    	F[0]=inf;
    	function<int()> find=[&]()->int{
    		int ans=0;
    		for(int i=1;i<=m;++i)
    			if(!vis[i] and F[i]<F[ans]) ans=i;
    		return ans;
    	};
    	for(int x=find();x;x=find()){
    		vis[x]=1;
    		for(int i=1;i<=m;++i)
    			if(R[x]+1-abs(T[x]-T[i])>=L[i]) F[i]=min(F[i],F[x]+C[i]);
    	}
    	int64 ans=inf;
    	for(int i=1;i<=m;++i)
    		if(R[i]==n) ans=min(ans,F[i]);
    	printf("%lld
    ",ans==inf?-1:ans);
    	return 0;
    }
    

    可以注意到,该动态规划的本质是Dijkstra,考虑优化这一个过程。

    注意到连向(F(i))的边的权值都是(C_i),所以在第一次能转移到它的时候直接认定它被完全松弛了。

    对转移条件的绝对值进行分类讨论后可以简化为:

    • (T_igeq T_j),则需满足(R_i−T_i+1geq L_j−T_j)

    • (T_i< T_j),则需满足(R_i+T_i+1geq L_j+T_j)

    (T_i)排序,然后用线段树来维护不等式条件。时间复杂度(O(mlog m))

    CO int N=1e5+10;
    CO int64 inf=1e18;
    struct node {int t,l,r,c;} A[N];
    priority_queue<pair<int64,int>,vector<pair<int64,int> >,greater<pair<int64,int> > > Q;
    int64 dis[N];
    
    namespace seg{
    	int minx[4*N],miny[4*N];
    	
    	#define lc (x<<1)
    	#define rc (x<<1|1)
    	#define mid ((l+r)>>1)
    	IN void push_up(int x){
    		minx[x]=min(minx[lc],minx[rc]);
    		miny[x]=min(miny[lc],miny[rc]);
    	}
    	void modify(int x,int l,int r,int p,int vx,int vy){
    		if(l==r) {minx[x]=vx,miny[x]=vy; return;}
    		if(p<=mid) modify(lc,l,mid,p,vx,vy);
    		else modify(rc,mid+1,r,p,vx,vy);
    		push_up(x);
    	}
    	void queryx(int x,int l,int r,int ql,int qr,int vx,vector<int>&ans){
    		if(ql>qr or minx[x]>vx) return;
    		if(ql<=l and r<=qr){
    			if(l==r){
    				ans.push_back(l);
    				minx[x]=miny[x]=INT_MAX;
    				return;
    			}
    			queryx(lc,l,mid,ql,qr,vx,ans);
    			queryx(rc,mid+1,r,ql,qr,vx,ans);
    			return push_up(x);
    		}
    		if(ql<=mid) queryx(lc,l,mid,ql,qr,vx,ans);
    		if(qr>mid) queryx(rc,mid+1,r,ql,qr,vx,ans);
    		push_up(x);
    	}
    	void queryy(int x,int l,int r,int ql,int qr,int vy,vector<int>&ans){
    		if(ql>qr or miny[x]>vy) return;
    		if(ql<=l and r<=qr){
    			if(l==r){
    				ans.push_back(l);
    				minx[x]=miny[x]=INT_MAX;
    				return;
    			}
    			queryy(lc,l,mid,ql,qr,vy,ans);
    			queryy(rc,mid+1,r,ql,qr,vy,ans);
    			return push_up(x);
    		}
    		if(ql<=mid) queryy(lc,l,mid,ql,qr,vy,ans);
    		if(qr>mid) queryy(rc,mid+1,r,ql,qr,vy,ans);
    		push_up(x);
    	}
    	#undef lc
    	#undef rc
    	#undef mid
    }
    
    int main(){
    	int n=read<int>(),m=read<int>();
    	for(int i=1;i<=m;++i)
    		read(A[i].t),read(A[i].l),read(A[i].r),read(A[i].c);
    	sort(A+1,A+m+1,[&](CO node&a,CO node&b)->bool{
    		return a.t<b.t;
    	});
    	for(int i=1;i<=m;++i){
    		if(A[i].l==1){
    			dis[i]=A[i].c,Q.push({A[i].c,i});
    			seg::modify(1,1,m,i,INT_MAX,INT_MAX);
    		}
    		else{
    			dis[i]=inf;
    			seg::modify(1,1,m,i,A[i].l-A[i].t,A[i].l+A[i].t);
    		}
    	}
    	while(Q.size()){
    		int x=Q.top().second;Q.pop();
    		vector<int> trans;
    		seg::queryx(1,1,m,1,x-1,A[x].r-A[x].t+1,trans);
    		seg::queryy(1,1,m,x+1,m,A[x].r+A[x].t+1,trans);
    		for(int y:trans)
    			dis[y]=dis[x]+A[y].c,Q.push({dis[y],y});
    	}
    	int64 ans=inf;
    	for(int i=1;i<=m;++i)
    		if(A[i].r==n) ans=min(ans,dis[i]);
    	printf("%lld
    ",ans==inf?-1:ans);
    	return 0;
    }
    
  • 相关阅读:
    laravel phpstorm IDE 代码提示
    vue的样式绑定
    asp.net mvc视图中使用entitySet类型数据时提示出错
    Linq to SQL 中将数字转换为字符串
    jquery submit()不能提交表单的解决方法
    命名空间“System.Web”中不存在类型或命名空间名称“Optimization”(是否缺少程序集引用?)
    没有为扩展名“.cshtml”注册的生成提供程序
    WP REST API: 设置和使用OAuth 1.0a Authentication(原文)
    解决"要执行请求的操作,WordPress需要访问您网页服务器的权限"
    Mysql添加用户错误:ERROR 1364 (HY000): Field 'ssl_cipher' doesn't have a default value解决方法
  • 原文地址:https://www.cnblogs.com/autoint/p/12690192.html
Copyright © 2020-2023  润新知