题目背景:
幻想乡的创始人之一,八云紫,有着强大的控制结界的能力,可以瞬间消除一定范围内
所有弹幕。我们可以将其消除范围视为一个矩形,而弹幕可以视为动点。
八云紫想要嘲讽她的敌人,所以她希望只使用一次消除能力,尽可能多地消除弹幕。
请你告诉她,在哪一时刻使用道具,可以消除尽可能多的弹幕。
问题描述:
在平面上给定一个矩形区域(也可能退化成线段或者点)。 矩形的边与坐标轴平行,左下端点为 (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 即可。
样例数据 1:
camera.in
2 2 2 3 3
3 1 -1 1
2 3 1 -1
camera.out
1
样例数据 2:
camera.in
13 44 68 49 73
40 46 2 6
28 75 4 -1
32 61 3 3
41 64 2 1
40 99 2 -7
54 49 -2 6
32 80 4 -2
73 99 -7 -7
23 93 6 -5
44 96 0 -6
36 70 3 0
70 98 -6 -7
75 53 -7 4
camera.out
4
数据范围:
对于前 40% 数据,
1<= n <= 100, 1 <= xl, xr, yl, yr, xi, yi <= 100, -10 <= ui, vi <= 10
对于 100% 数据,
1<= n <= 10^5, 1 <= xl, xr, yl, yr, xi, yi <= 10^9, 0 <= |ui|, |vi|<= 10^5, xl <= xr, yl <= yr
保证 n,xl,xr,yl,yr,xi,yi,ui,vi 均为整数.
【题解】
算法一:
直接模拟,计算每个时刻矩形内点的个数。
期望得分:40 分
算法二:
我们可以发现只有动点进入矩形或者离开矩形会影响矩形内点的个数,计算出每个动点在矩形内的时间段,记录 2*n 个事件点并计算对应时刻矩形内点的个数即可。
时间复杂度: O(n)
期望得分: 100 分
发现每个点经过矩形的时间是一个区间,然后求区间上最多被覆盖的次数。并且坐标轴上的问题要用到离散化,只有一个公式但是要分类讨论。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#define y0 yyychushipos
using namespace std;
const int MAX=100005;
int T[MAX<<1],o[MAX<<1],line[MAX<<1];
int ru[MAX],chu[MAX];
int N,XL,YL,XR,YR,x0,y0,u,v,mx,ans,res,tot,cnt;
inline int gi()
{
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=-1,ch=getchar();
while (ch>='0'&&ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*w;
}
inline bool check(int x,int y)
{
return (x>=XL&&x<=XR&&y>=YL&&y<=YR);
}
inline int calc()
{
if (check(x0,y0)) return 0;
int t1=-1,t2=-1;
if (x0<XL&&y0<YL)
{
if (!(u>0&&v>0)) return -1;
t1=(XL-x0+u-1)/u;
t2=(YL-y0+v-1)/v;
int x1=x0+u*t1,y1=y0+v*t1;
int x2=x0+u*t2,y2=y0+v*t2;
if ( check(x1,y1) ) return t1;
else if ( check(x2,y2) ) return t2;
return -1;
}
else if (x0>XR&&y0<YL)
{
if (!(u<0&&v>0)) return -1;
u*=-1;
t1=(x0-XR+u-1)/u;
t2=(YL-y0+v-1)/v;
int x1=x0-u*t1,y1=y0+v*t1;
int x2=x0-u*t2,y2=y0+v*t2;
u*=-1;
if ( check(x1,y1) ) return t1; else if ( check(x2,y2) ) return t2;
return -1;
}
else if (x0<XL&&y0>YR)
{
if (!(u>0&&v<0)) return -1;
v*=-1;
t1=(XL-x0+u-1)/u;
t2=(y0-YR+v-1)/v;
int x1=x0+u*t1,y1=y0-v*t1;
int x2=x0+u*t2,y2=y0-v*t2;
v*=-1;
if ( check(x1,y1) ) return t1; else if ( check(x2,y2) ) return t2;
return -1;
}
else if (x0>XR&&y0>YR)
{
if (!(u<0&&v<0)) return -1;
u*=-1;v*=-1;
t1=(x0-XR+u-1)/u;
t2=(y0-YR+v-1)/v;
int x1=x0-u*t1,y1=y0-v*t1;
int x2=x0-u*t2,y2=y0-v*t2;
u*=-1;v*=-1;
if ( check(x1,y1) ) return t1; else if ( check(x2,y2) ) return t2;
return -1;
}
else if (x0<XL)
{
if (u<=0) return -1;
t1=(XL-x0+u-1)/u;
int xx=x0+u*t1,yy=y0+v*t1;
if (check(xx,yy)) return t1;
return -1;
}
else if (x0>XR)
{
if (u>=0) return -1;
u*=-1;
t1=(x0-XR+u-1)/u;
int xx=x0-u*t1,yy=y0+v*t1;
u*=-1;
if (check(xx,yy)) return t1;
return -1;
}
else if (y0<YL)
{
if (v<=0) return -1;
t1=(YL-y0+v-1)/v;
int xx=x0+u*t1,yy=y0+v*t1;
if (check(xx,yy)) return t1;
return -1;
}
else if (y0>YR)
{
if (v>=0) return -1;
v*=-1;
t1=(y0-YR+v-1)/v;
int xx=x0-u*t1,yy=y0+v*t1;
v*=-1;
if (check(xx,yy)) return t1;
return -1;
}
return -1;
}
inline int find(int x)
{
int l=1,r=cnt;
while (l<r)
{
int mid=(l+r+1)>>1;
if (T[mid]<=x) l=mid;
else r=mid-1;
}
return l;
}
int main()
{
freopen("camera.in","r",stdin);
freopen("camera.out","w",stdout);
N=gi();XL=gi();YL=gi();XR=gi();YR=gi();
for (int i=1;i<=N;i++)
{
x0=gi();y0=gi();u=gi();v=gi();
res=calc();
if (res==-1) continue;
ru[i]=res;o[++tot]=res;
int l=res,r=1000000000;
while (l<r)
{
int mid=(l+r+1)>>1;
int xxx=x0+u*mid,yyy=y0+v*mid;
if ( check(xxx,yyy) ) l=mid;
else r=mid-1;
}
l++;
res=l;
chu[i]=res;o[++tot]=res;
}
sort(o+1,o+tot+1);
for (int i=1;i<=tot;i++)
if (i==1||o[i]!=o[i-1]) T[++cnt]=o[i];
for (int i=1;i<=N;i++)
{
int pos1=find(ru[i]),pos2=find(chu[i]);
line[pos1]++;line[pos2]--;
}
for (int i=1;i<=cnt;i++)
{
line[i]+=line[i-1];
if (line[i]>mx) mx=line[i],ans=T[i];
}
printf("%d",ans);
return 0;
}