P11232 [CSP-S 2024] 超速检测

考场差点切掉,分类讨论讨论少了,被民间数据卡掉最后两个点。

Update

24/10/27 0:12 初稿

P11232 [CSP-S 2024] 超速检测(民间数据)

一条路,长 \(L\) ,路上有 \(n\) 辆车在行驶,其驶入这条路的坐标为 \(d_i\) ,速度为 \(v_i\) ,加速度为 \(a_i\) 。当车的坐标为 \(L\) 或速度为 \(0\) 时,视为驶出这条路。

已知这条路限速 \(V\) ,路上有 \(m\) 个监控, 坐标为 \(p_j\) 。一辆车被认为超速,当且仅当其在某个监控处的速度 \(v_t > V\)

求:

  1. 被认为超速的车有多少辆;
  2. 在确保所有超速的车都被认为是超速的情况下,可以关掉多少监控。

提示

匀加速直线运动,即为加速度恒定的直线运动。高中的OIer们一定很熟悉。为了让初中或小学的OIer们也能看懂题目,给出几个公式:

  1. \(v_t=v_0+at\)
  2. \(x_t=x_0+v_0t+\frac{1}{2}at^2\)
  3. \({v_t}^2-{v_0}^2=2as\)

其中,本篇题解仅用公式3,因为该公式阐明了速度与加速度、位移之间的关系。

思路

第一问

首先,对于 \(a_i=0\) 的车,若 \(v_i>0\) ,只要其被监控拍到,其即为超速车辆。

由此得出下式:

$is_i = ( v_i > v ) \wedge (d_i \le p_m) $

其次,对于 \(a_i>0\) 的车,已知,其速度单调增加,只要其在最后一个监控被认为是超速的,其即为超速车辆。

运用公式3可得:

\({v_t}^2={v_i}^2+2a_i\cdot(p_m-d_i)\)

注意到:公式中的 \(v\) 的次数,全部为 \(2\) ,而使用浮点数可能有精度丢失,所以我们把所有 \(v\) 直接平方。

所以:

\(is_i = ({v_i}^2+2a_i\cdot(p_m-d_i)>V^2) \wedge (d_i \le p_m)\)

最后,对于 \(a_i<0\) 的车,其速度单调下降,所以,我们判断其在其遇到的第一个监控是否超速即可。

记该监控为 \(t\) ,则有:

\(is_i=({v_i}^2+2a_i\cdot(p_t-d_i)>V^2)\wedge(t\le m)\)

由此,第一问解决完毕。

第二问

不难发现:

一辆车被认为超速的监控编号是连续的。所以第二问被转化为坐标轴上的 \(n\) 条线段,最少用多少个点可以覆盖这些线段。

如样例一( \(O\) 为被监控拍到超速;\(-\)为未超速):

\(p_1=2\) \(p_2=5\) \(p_3=8\) \(p_4=9\) \(p_5=15\)
1 \(-\) \(-\) \(-\) \(-\) \(-\)
2 \(O\)
3 \(O\) \(O\) \(O\) \(O\)
4 \(O\) \(O\)
5 \(-\) \(-\) \(-\) \(-\) \(-\)

这个问题可以通过贪心求解:

把所有线段按照右端点排序,遍历所有线段,若一个线段没有被排序,则使用其右端点进行覆盖。

代码

#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+50;
int T,n,m,L,V;
int d[N],v[N],a[N],p[N],ans1,ans2;
struct node{
	int l,r;
	bool operator <(const node t)const{return r<t.r;}
}q[N];
bool is[N];//这个数组其实没必要写,不过也不差这点空间
void solve(){
	cin>>n>>m>>L>>V;
    V=V*V;
    ans2=m;
    ans1=0;//多测要清零
	for(int i=1;i<=n;++i){
		cin>>d[i]>>v[i]>>a[i];
        v[i]=v[i]*v[i];
	}
	for(int i=1;i<=m;++i)cin>>p[i];
	for(int i=1;i<=n;++i){
		if(a[i]>=0){//a=0时,下式退化为v[i]>V
			is[i]=(v[i]+2*a[i]*(p[m]-d[i])>V)&(d[i]<=p[m]);
			if(a[i]==0)
                q[i].l=is[i]?lower_bound(p+1,p+1+m,d[i])-p:0;
			else
                q[i].l=is[i]?lower_bound(p+1,p+1+m,max(0,(int)ceil((V-v[i])/2.0/a[i]))+d[i])-p:0;//速度加到V处的坐标
			q[i].r=is[i]?m:0;
		}
		else{
			int t=lower_bound(p+1,p+1+m,d[i])-p;//第一个遇见的监控
			is[i]=(v[i]+2*a[i]*(p[t]-d[i])>V)&(t<=m);
			q[i].l=is[i]?t:0;
			q[i].r=is[i]?lower_bound(p+1,p+1+m,(int)ceil((V-v[i])/2.0/a[i])+d[i])-p-1:0;//速度减到V处的坐标
		}
		ans1+=is[i];//统计第一问的答案
	}
	sort(q+1,q+1+n);
	for(int i=1,lst=0;i<=n;++i){//统计第二问的答案
		if(q[i].l>lst){
			lst=q[i].r;--ans2;
		}
	}
	cout<<ans1<<" "<<ans2<<endl;
}
int main(){
	cin>>T;
	while(T--)solve();
	return 0;
}

结尾

注意一些细节。

  • \(v_t>V\) 才为超速,\(v_t = V\) 不算

  • lower_bound和upper_bound的区别,以及末尾是否 \(-1\)

  • 多测要清空

posted @ 2024-10-27 00:09  Xie2Yue  阅读(314)  评论(0)    收藏  举报