hdu5714 排序+前缀和

首先需要知道视角就是平时理解的视角(角度),题目中说垂直河岸容易误导。然后需要注意的是看到完整的船只。
思路:对于每条船,能观察到它完整的观测点区间为(y-z,x+z),把区间存储。接下来的排序比较关键:先按点的位置从小到大排,如果位置相同则前端点排前面(对于向右船只的区间,左端点为前端点;向右的区间,右端点为前端点。 这样算出来的才能是区间重叠的最大值,这里需要想一想),如果前面二者都相等,则向右的排前面(此时对应相向而行,必然会相遇)。最后再用前缀和思想先从左向右计算向右区间中每个点之前覆盖的最大值ans[i],然后再从右向左计算向左区间中(每个点对应区间覆盖值j+ans[i]),比较出最大值即可。
注意数组一定要开足够大,不然会TLE,原来数组越界也可能TLE。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<iostream>
#include<vector>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e5+50;
int ans[maxn],n;///ans[i]记录1到i的最多的观测向右的船只的区间覆盖 

struct node{
	int end_type,dir,end_loc;
	node(int tt,int dd,int ll):end_type(tt),dir(dd),end_loc(ll){
	}
};
vector<node> vec;

bool cmp(node a,node b){
	if(a.end_loc!=b.end_loc) return a.end_loc<b.end_loc;
	if(a.end_type!=b.end_loc) return a.end_type<b.end_type;///因为找覆盖次数最大的区间,所以起点先放前面 
	return a.dir>b.dir;///右边的放前面 
}

int main(){
	int t;
	while(scanf("%d",&t)!=EOF){
		int casenum=0;
		while(t--){
			vec.clear();
			vec.push_back(node(inf,inf,inf));///往后空一位 
			int x,y,z,d,left_end,right_end;
			//memset(ans,0,sizeof(ans)); 
			scanf("%d",&n);
			for(int i=0;i<n;i++){
				scanf("%d%d%d%d",&x,&y,&z,&d);
				left_end=y-z;
				right_end=x+z;
				if(left_end<=right_end){
					vec.push_back(node(1,d,left_end));
					vec.push_back(node(2,d,right_end));
				}		
			}
			sort(++vec.begin(),vec.end(),cmp); 
			ans[0]=0;
			int temp=0;///temp记录到某个位置此时的区间覆盖 
			for(int i=1;i<vec.size();i++){///从左往右找向右的区间 
				if(vec[i].dir==1){
					if(vec[i].end_type==1) temp++;///如果是左端点自加   
					if(vec[i].end_type==2) temp--;///右端点自减 
				}
				ans[i]=max(temp,ans[i-1]);
			}
			temp=0;
			int t=0,f=0;
			for(int i=vec.size()-1;i>0;i--)///这里需要反过来,因为先走右端点 从右往左找向左的区间 
				if(vec[i].dir==-1){
					if(vec[i].end_type==2) temp++;
					t=max(temp,t);///到目前的最大区间覆盖值
					f=max(f,t+ans[i]);
					if(vec[i].end_type==1) temp--; 
				}
			printf("Case #%d:\n%d\n",++casenum,f);
		}
	} 
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值