[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;
}