[CSP-S 2024] 超速检测 AC满分代码

题目描述

小 D 新入职了某国的交管部门,他的第一个任务是负责国家的一条长度为 LL 的南北主干道的车辆超速检测。为了考考小 D,上司首先需要他解决一个简化的场景。

这个周末,主干道上预计出现 nn 辆车,其中第 ii 辆车从主干道上距离最南端 d_idi​ 的位置驶入,以 v_ivi​ 的初速度和 a_iai​ 的加速度做匀加速运动向北行驶。我们只考虑从南向北的车辆,故 v_i > 0vi​>0,但 a_iai​ 可正可负,也可以为零。当车辆行驶到主干道最北端(即距离最南端为 LL 的位置)或速度降为 00(这只可能在 a_i < 0ai​<0 时发生)时,我们认为该车驶离主干道。

主干道上设置了 mm 个测速仪,其中第 jj 个测速仪位于主干道上距离最南端 p_jpj​ 的位置,每个测速仪可以设置开启或关闭。当某辆车经过某个开启的测速仪时,若这辆车的瞬时速度超过了道路限速 VV,那么这辆车就会被判定为超速。注意当车辆驶入与驶出主干道时,如果在对应位置有一个开启的测速仪,这个测速仪也会对这辆车进行测速。

上司首先想知道,如果所有测速仪都是开启的,那么这 nn 辆车中会有多少辆车被判定为超速。

其次,为了节能,部门想关闭一部分测速仪。然而,他们不希望漏掉超速的车,也就是说,当 nn 辆车里的某辆车在所有测速仪都开启时被判定为超速,他们希望在关闭一部分测速仪以后它依然被判定为超速。上司还想知道在这样的条件下最多可以关闭多少测速仪。

由于 nn 很大,上司允许小 D 使用编程解决这两个问题,于是小 D 找到了你。

如果你对于加速度并不熟悉,小 D 贴心地在本题的“提示”部分提供了有关加速度的公式。

输入格式

输入的第一行包含一个正整数 TT,表示数据组数。

接下来包含 TT 组数据,每组数据的格式如下:

第一行包含四个整数 n, m, L, Vn,m,L,V,分别表示车辆数量、测速仪数量、主干道长度和道路限速。

接下来 nn 行:

第 ii 行包含三个整数 d_i, v_i, a_idi​,vi​,ai​ 描述一辆车。

最后一行包含 mm 个整数 p_1, p_2, \dots , p_mp1​,p2​,…,pm​ 描述道路上所有测速仪的位置。

输出格式

对于每组数据:输出一行包含两个整数,第一个整数为所有测速仪都开启时被判定为超速的车辆数量,第二个整数为在不漏掉超速车辆的前提下最多可以关闭的测速仪数量。

输入输出样例

输入 #1复制

1
5 5 15 3
0 3 0
12 4 0
1 1 4
5 5 -2
6 4 -4
2 5 8 9 15

输出 #1复制

3 3

说明/提示

【样例 1 解释】

在该组测试数据中,主干道长度为 1515,限速为 33,在距离最南端 2, 5, 8, 9, 152,5,8,9,15 的位置各设有一个测速仪。

  • 第一辆车在最南端驶入,以 33 的速度匀速行驶。这辆车在整个路段上都没有超速。
  • 第二辆车在距离最南端 1212 的位置驶入,以 44 的速度匀速行驶。在最北端驶离主干道时,它会被距离最南端 1515 的测速仪判定为超速。
  • 第三辆车在距离最南端 11 的位置驶入,以 11 的初速度、44 的加速度行驶。其在行驶了 \frac{3^2-1^2}{2\times 4}=12×432−12​=1 的距离,即到达 22 的位置时,速度变为 33,并在之后一直超速。因此这辆车会被除了距离最南端 22 的测速仪以外的其他测速仪判定为超速。
  • 第四辆车在距离最南端 55 的位置驶入,以 55 的初速度、-2−2 的加速度行驶。其在行驶了 \frac{3^2-5^2}{2\times (-2)}2×(−2)32−52​ 的距离,即到达 99 的位置时,速度变为 33。因此这辆车在距离最南端 [5, 9)[5,9) 时超速,会被距离最南端 55 和 88 的两个测速仪判定为超速。
  • 第五辆车在距离最南端 6 的位置驶入,以 4 的初速度、−4 的加速度行驶。在其行驶了 \frac{3^2-4^2}{2\times (-4)}=\frac{7}{8}2×(−4)32−42​=87​ 的距离后,即这辆车到达 6\frac{7}{8}687​ 的位置时,其速度变为 33。因此这辆车在距离最南端 [6,6\frac{7}{8})[6,687​) 时超速,但这段区间内没有测速仪,因此不会被判定为超速。

因此第二、三、四辆车会被判定为超速,输出的第一个数为 33。

我们可以关闭距离最南端 2, 8, 92,8,9 的三个测速仪,保留 55 和 1515 的两个测速仪,此时三辆之前被判定为超速的车依然被判定为超速。可以证明不存在更优方案,因此输出的第二个数为 33。

#include <bits/stdc++.h> 
using namespace std; 

const int N=1e5+2,L=1e6+2;
int t,n,m,l,V,tmp,ans1,ans2;
int d[N],v[N],a[N],p[N];
int lft[L],rgt[L]; //距离最近的测速仪编号 
int ld[N],rd[N]; //每辆车超速区间的左、右端点
int g[N]; //所有超速的车的编号
int id; //后面贪心用的 

bool cmp(int x,int y){
	return rd[x]<rd[y];
}

void solve(){
	//1.常规读入+初始化
	ans1=ans2=0,id=-1;
	cin>>n>>m>>l>>V;
	for(int i=1;i<=n;++i)
		cin>>d[i]>>v[i]>>a[i];
	for(int i=1;i<=m;++i){
		cin>>p[i];
		lft[p[i]]=rgt[p[i]]=i; //这一行是2.的步骤,提前到这 
	}
	//2.预处理距离最近的测速仪编号 
	p[0]=0,p[m+1]=l+1;
	for(int i=0;i<=m;++i)
		for(int j=p[i]+1;j<p[i+1];++j)
			lft[j]=i,rgt[j]=i+1;
	//3.计算每辆车的超速区间(本题核心)
	for(int i=1;i<=n;++i){
		if(d[i]>p[m]) continue; //如果驶入的位置之后没有测速仪就不理它了 
		if(a[i]==0){
			if(v[i]>V){
				g[++ans1]=i;
				ld[i]=rgt[d[i]];
				rd[i]=m;
			} //一开始就超速 
		}
		else if(a[i]>0){
			if(v[i]>V){
				g[++ans1]=i;
				ld[i]=rgt[d[i]];
				rd[i]=m;
			} //一开始就超速
			else{
				tmp=V*V-v[i]*v[i];
				if(tmp%(2*a[i])==0){ //要注意当恰好到V的时候 不算超速 所以序号需要加1
					tmp=d[i]+tmp/(2*a[i]); //当车行驶到这里时提速到V 
					if(tmp<p[m]){
						g[++ans1]=i;
						ld[i]=rgt[tmp+1];
						rd[i]=m;
					} //在p[m]处恰好提速到V是不算的 
				}
				else{
					tmp=d[i]+tmp/(2*a[i])+1;
					if(tmp<=p[m]){
						g[++ans1]=i;
						ld[i]=rgt[tmp];
						rd[i]=m;
					}
				} 
			} //加速了一会儿才超速 
		}
		else{
			if(v[i]>V){
				tmp=v[i]*v[i]-V*V;
				if(tmp%(-2*a[i])==0){ 
					tmp=d[i]+tmp/(-2*a[i]);
					if(tmp>p[m]){
						g[++ans1]=i;
						ld[i]=rgt[d[i]];
						rd[i]=m;
					}
					else{
						ld[i]=rgt[d[i]];
						rd[i]=lft[tmp-1];
						if(rd[i]>=ld[i]) g[++ans1]=i;
					}
				}
				else{
					tmp=d[i]+tmp/(-2*a[i]);
					if(tmp>=p[m]){
						g[++ans1]=i;
						ld[i]=rgt[d[i]];
						rd[i]=m;
					}
					else{
						ld[i]=rgt[d[i]];
						rd[i]=lft[tmp];
						if(rd[i]>=ld[i]) g[++ans1]=i;
					}
				}
			} //一开始超速,后面减速 
		} 
	}
	//4.计算最少需要开启的测速仪数量(贪心)
	sort(g+1,g+1+ans1,cmp);
	for(int i=1;i<=ans1;++i)
		if(ld[g[i]]>id){
			id=rd[g[i]];
			++ans2;
		} //如果左端点没有被覆盖到,那就在右端点覆盖 
	cout<<ans1<<" "<<m-ans2<<endl;
}

int main(){
	cin>>t;
	while(t--) solve(); 
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值