cogs1995. Yukari解题报告

题目背景:

       幻想乡的创始人之一,八云紫,有着强大的控制结界的能力,可以瞬间消除一定范围内所有弹幕。我们可以将其消除范围视为一个矩形,而弹幕可以视为动点。

       八云紫想要嘲讽她的敌人,所以她希望只使用一次消除能力,尽可能多地消除弹幕。

       请你告诉她,在哪一时刻使用道具,可以消除尽可能多的弹幕。

 

 

问题描述:

       在平面上给定一个矩形区域(也可能退化成线段或者点)。

       矩形的边与坐标轴平行,左下端点为 (xl,yl),右上端点为 (xr,yr)。

       给定 n 个动点,初始坐标为 (xi, yi),运动方向为 (ui,vi),速度为 sqrt((ui)^2+(vi)^2)

       求在哪一时刻 t (t ∈ N),在矩形内部及边界的动点数目最多。

       如果有多个 t 满足条件,输出最小的 t 即可。

 

 

输入格式:

       第一行 5 个正整数,n, xl, yl, xr, yr,表示动点个数和矩形区域。

       接下来 n 行,每行 4 个整数,xi, yi, ui, vi ,描述第 i 个动点。

 

 

输出格式:

        在矩形内部及边界的动点数目最多的时刻 t (t ∈ N)。

       如果有多个 t 满足条件,输出最小的 t 即可。

题解:
预处理之后 对时间差分

点只会与矩形框内两次(端点视为两次 便于处理)

那么进入时间a影响到的点就是ceil(a)

出去时间b影响到的点就是floor(b)+1

将时间离散化(整数)

然后就可以O(n)求解

细节什么的很麻烦

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=100000+10;
double x[maxn],y[maxn],u[maxn],v[maxn];
int t[maxn],z[maxn];
int B[maxn*2];
int hash[maxn*2];
int tot,sz1,sz2,tt;
double xx,yy,uu,vv;
inline int bs(int x){
	int l=1,r=tot;
	while(l+1<r){
		int mid=(l+r)>>1;
		if(hash[mid]>=x)
			r=mid;
		else l=mid+1;
	}
	if(hash[l]==x)
		return l;
	return r;
}
int main(){
	freopen("camera.in","r",stdin);
	freopen("camera.out","w",stdout);
	int n;
	scanf("%d %lf %lf %lf %lf",&n,&xx,&yy,&uu,&vv);
	for(int i=1;i<=n;i++){
		scanf("%lf %lf %lf %lf",&x[i],&y[i],&u[i],&v[i]);
		if(x[i]>=xx&&x[i]<=uu&&y[i]>=yy&&y[i]<=vv){
			t[++sz1]=0;
			if(u[i]==0){
				double a=(vv-y[i])/v[i];
				double b=(yy-y[i])/v[i];
				if(a>0)
					z[++sz2]=int(floor(a))+1;
				else z[++sz2]=int(floor(b))+1;
			}
			else if(v[i]==0){
				double a=(uu-x[i])/u[i];
				double b=(xx-x[i])/u[i];
				if(a>0)
					z[++sz2]=int(floor(a))+1;
				else z[++sz2]=int(floor(b))+1;
			}
			else {
				double a=(uu-x[i])/u[i];
				double b=(xx-x[i])/u[i];
				double c=(vv-y[i])/v[i];
				double d=(yy-y[i])/v[i];
				double p,q;
				if(a>0)
					p=a;
				else p=b;
				if(c>0)
					q=c;
				else q=d;
				z[++sz2]=int(floor(min(p,q)))+1;
			}
			continue;
		}
		if(u[i]==0){
			if(x[i]>=xx&&x[i]<=uu){
				double a=(yy-y[i])/v[i];
				double b=(vv-y[i])/v[i];
				if(a>b)
					swap(a,b);
				if(a>=0)
					t[++sz1]=int(ceil(a));
				if(b>=0)
					z[++sz2]=int(floor(b))+1;
			}
		}
		else if(v[i]==0){
			if(y[i]>=yy&&y[i]<=vv){
				double a=(xx-x[i])/u[i];
				double b=(uu-x[i])/u[i];
				if(a>b)
					swap(a,b);
				if(a>=0)
					t[++sz1]=int(ceil(a));
				if(b>=0)
					z[++sz2]=int(floor(b))+1;
			}
		}
		else {
			double k=v[i]/u[i];
			double b=y[i]-x[i]*k;
			double tl=k*xx+b;
			double p,q;
			int ph=0,qh=0;
			if(tl>=yy&&tl<=vv){
				if((xx-x[i])/u[i]>=0){
					if(!ph){
						p=(xx-x[i])/u[i];
						ph=1;
					}
					else if(!qh){
						qh=1;
						q=(xx-x[i])/u[i];
					}
				}
			}
			tl=k*uu+b;
			if(tl>=yy&&tl<=vv){
				if((uu-x[i])/u[i]>=0){
					if(!ph){
						p=(uu-x[i])/u[i];
						ph=1;
					}
					else if(!qh){
						qh=1;
						q=(uu-x[i])/u[i];
					}
				}
			}
			tl=(yy-b)/k;
			if(tl>=xx&&tl<=uu){
				if((yy-y[i])/v[i]>=0){
					if(!ph){
						p=(yy-y[i])/v[i];
						ph=1;
					}
					else if(!qh){
						qh=1;
						q=(yy-y[i])/v[i];
					}
				}
			}
			tl=(vv-b)/k;
			if(tl>=xx&&tl<=uu){
				if((vv-y[i])/v[i]>=0){
					if(!ph){
						p=(vv-y[i])/v[i];
						ph=1;
					}
					else if(!qh){
						qh=1;
						q=(vv-y[i])/v[i];
					}
				}
			}
			if(q<p)
				swap(q,p);
			t[++sz1]=int(ceil(p));
			z[++sz2]=int(floor(q))+1;
		}
	}
	for(int i=1;i<=sz1;i++)
		B[++tt]=t[i];
	for(int i=1;i<=sz2;i++)
		B[++tt]=z[i];
	sort(B+1,B+tt+1);
	hash[++tot]=B[1];
	for(int i=2;i<=tt;i++)
		if(B[i]!=B[i-1])
			hash[++tot]=B[i];
	memset(B,0,sizeof(B));
	for(int i=1;i<=sz1;i++){
		int q=bs(t[i]);
		B[q]++;
	}
	for(int i=1;i<=sz2;i++){
		int q=bs(z[i]);
		B[q]--;
	}
	int ans=0,tim;
	for(int i=1;i<=tot;i++){
		B[i]+=B[i-1];
		if(B[i]>ans){
			ans=B[i];
			tim=hash[i];
		}
		else if(B[i]==ans&&hash[i]<=tim){
			ans=B[i];
			tim=hash[i];
		}
	}
	printf("%d\n",tim);
return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值