[CSP-S 2024] 超速检测 题解

[CSP-S 2024] 超速检测 题解


知识点

二分,贪心,物理

题意简述

给你一条长为 \(L\) 的公路。

\(n\) 辆车在做同向的匀速直线运动或匀变速直线运动,给定它们的起点 \(d_i\),初速度 \(v_i\),加速度 \(a_i\)(匀速直线运动时 \(a_i=0\))。

设置了限速 \(V\)\(m\) 个测速摄像头,给定它们的位置 \(p_i\)

问:有多少辆车会被测速摄像头抓到超速,以及最少留下多少个摄像头还是能抓到所有这些超速的车。

分析

对于超速的车,能抓拍到它的摄像头一定是一个连续的区间,那么我们只要求最少有多少个点(摄像头)的并能够与所有区间有交即可。

首先我们对于一辆车可以以 \(a_i\)\(0\) 的关系来分类讨论:

  • \(a_i \ge 0\)

    一直不超速或从某个点开始一直超速,超速区间:从开始超速的点一直到最后一个点。

  • \(a_i<0\)

    一直不超速或从能到的第一个点一直超速,到某个点不超速,超速区间:从能到的第一个点一直到最后一个超速的点。

区间都可以简单地二分处理出来。

接下来考虑求:最少有多少个点(摄像头)的并能够与所有区间有交。

我们小范围部分分可以选择状压,特殊性质 A,B 可以特判。

考虑正解。我们贪心地想:将区间按右端点升序排序,然后不断取最小的右端点,再把能取到的区间去掉,就可以既保证正确性,又保证最优性地解决这个问题。

代码

时间复杂度:\(O(Tn(\log_2{n}+\log_2{m}))\),空间复杂度:\(O(n+m)\)

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define Fi first
#define Se second
#define ll long long
#define Pii pair<int,int>
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define FOR(i,a,b) for(int i(a);i<=(int)(b);++i)
#define DOR(i,a,b) for(int i(a);i>=(int)(b);--i)
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define EDGE(g,i,x,y) for(int i=(g).h[(x)],y=(g)[(i)].v;~i;y=(g)[i=(g)[i].nxt].v)
#define main Main();signed main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);return Main();}signed Main
using namespace std;
constexpr int N(1e5+10);
namespace IOstream {
#define getc() getchar()
#define putc(ch) putchar(ch)
#define isdigit(ch) ('0'<=(ch)&&(ch)<='9')
	template<class T>void rd(T &x) {
		static bool sign(0);
		static char ch(0);
		for(x=0,sign=0,ch=getc();!isdigit(ch);ch=getc())if(ch=='-')sign=1;
		for(;isdigit(ch);x=(x<<1)+(x<<3)+(ch^'0'),ch=getc());
		if(sign)x=-x;
	}
	template<class T>void wr(T x,const char End='\n') {
		static int top(0);
		static int st[50];
		do st[++top]=x%10,x/=10;
		while(x);
		while(top)putc(st[top]^'0'),--top;
		putc(End);
	}
} using namespace IOstream;
int Cas,n,m,L,V,ans;
int p[N];
struct Car {
	int d,v,a,l,r;
	void Scan() {
		rd(d),rd(v),rd(a),l=r=-1;
	}
	int Begin() {
		return lower_bound(p+1,p+m+1,d)-p;
	}
	int End() {
		return a>=0?m:upper_bound(p+1,p+m+1,d-v*v/(a<<1))-p-1;
	}
	void Range() {
		int L(Begin());
		if(!a)return v>V&&L<=m?(l=L,r=m):(l=r=-1),void();
		if(a>0) {
			int res(m+1);
			for(int l(Begin()),r(m),mid((l+r)>>1);l<=r;mid=(l+r)>>1)
				(ll)v*v+2ll*a*(p[mid]-d)>V*V?res=mid,r=mid-1:l=mid+1;
			return res<=m?(l=res,r=m):(l=r=-1),void();
		}
		int res(0);
		for(int l(L),r(End()),mid((l+r)>>1);l<=r;mid=(l+r)>>1)
			(ll)v*v+2ll*a*(p[mid]-d)>V*V?res=mid,l=mid+1:r=mid-1;
		return L<=res?(l=L,r=res):(l=r=-1),void();
	}
} a[N];
namespace Subtask1 {
#define lowbit(i) ((i)&-(i))
	const int N(20+10),St((1<<20)+10);
	int Un,Um;
	int f[St],Lg[St],cnt[St],sta[N];
	bool Check() {
		return n<=20&&m<=20;
	}
	void Init() {
		FOR(S,2,St-5)Lg[S]=Lg[S>>1]+1;
		FOR(S,1,St-5)cnt[S]=cnt[S>>1]+(S&1);
	}
	int Cmain() {
		Un=(1<<n)-1,Um=(1<<m)-1,RCL(sta+1,0,int,m);
		FOR(i,1,m)FOR(j,1,n)if(a[j].l<=i&&i<=a[j].r)sta[i]|=1<<(j-1);
		FOR(S,1,Um)f[S]=f[S^lowbit(S)]|sta[Lg[lowbit(S)]+1];
		FOR(S,1,Um)if(f[S]==Un)tomax(ans,m-cnt[S]);
		wr(n,' '),wr(ans);
		return 0;
	}
#undef lowbit
}
namespace SubtaskAB {
	bool Check() {
		FOR(i,1,n)if(a[i].a<0)return 0;
		return 1;
	}
	int Cmain() {
		wr(n,' '),wr(n>0?m-1:m);
		return 0;
	}
}
namespace Subtask {
	bool vis[N];
	struct node {
		int l,r,idx;
	};
	auto cmp1=[](node a,node b) {
		return a.l^b.l?a.l>b.l:a.r>b.r;
	};
	auto cmp2=[](node a,node b) {
		return a.r^b.r?a.r>b.r:a.l>b.l;
	};
	priority_queue<node,vector<node>,decltype(cmp1)> q1(cmp1);
	priority_queue<node,vector<node>,decltype(cmp2)> q2(cmp2);
	bool Cmain() {
		int R(0);
		RCL(vis+1,0,bool,n),ans=m;
		FOR(i,1,n)q1.push((node){a[i].l,a[i].r,i}),q2.push({a[i].l,a[i].r,i});
		while(!q1.empty()||!q2.empty()) {
			while(!q1.empty()&&(q1.top().l<=R||vis[q1.top().idx]))vis[q1.top().idx]=1,q1.pop();
			if(q1.empty())break;
			while(!q2.empty()&&vis[q2.top().idx])q2.pop();
			if(q2.empty())break;
			--ans,R=q2.top().r,vis[q2.top().idx]=1,q2.pop();
		}
		wr(n,' '),wr(ans);
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		return 0;
	}
}
int Cmain() {
	rd(n),rd(m),rd(L),rd(V),ans=0;
	FOR(i,1,n)a[i].Scan();
	FOR(i,1,m)rd(p[i]);
	FOR(i,1,n)a[i].Range();
	int tmp(0);
	FOR(i,1,n)if(~a[i].l&&~a[i].r&&a[i].l<=a[i].r)a[++tmp]=a[i];
	n=tmp;
	if(SubtaskAB::Check())return SubtaskAB::Cmain();
	if(Subtask1::Check())return Subtask1::Cmain();
	return Subtask::Cmain();
}
signed main() {
	for(Subtask1::Init(),rd(Cas);Cas;--Cas)Cmain();
	return 0;
}

posted @ 2024-11-13 14:03  Add_Catalyst  阅读(17)  评论(0编辑  收藏  举报