感觉这种位置指针跳来跳去的题好难写对,记录一下套路。
传送门:https://www.luogu.com.cn/problem/UVA10382
思路比较简单:处理一下每个装置的有效左右区间(显然半径刚好能够到达的点是临界),然后从左到右贪心地选取装置:具体来说就是维护一个前缀的控制区域(只需维护最右的端点),控制区域内是一个装置左边界的集合,我们从这个集合出发考察右边界的最大值,得到最大值后更新控制区域,如此下去即可。
while(cur<l){ // 只要控制区域的最右没有到达草坪的最右,就继续更新
double np=cur; // new point 记录控制区域右端点。
for(; p<=n && q[p].x<=cur; p++) np=max(np, q[p].y); // p 维护前缀点集的装置编号,np 从中更新最右点。
if(np==cur && cur<l){ // 如果np没有得到更新而且无法到达终点,无解。
ok=false;
break;
}
res++; // 更新答案
cur=np; // 更新控制区域
}
#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;
#define endl '
'
#define debug(x) cerr << #x << ": " << x << endl
#define pb(a) push_back(a)
#define set0(a) memset(a,0,sizeof(a))
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)
#define ceil(a,b) (a+(b-1))/b
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define ll_INF 0x7f7f7f7f7f7f7f7f
typedef long long ll;
typedef pair<int,int> PII;
typedef pair<double,double> PDD;
#define x first
#define y second
inline void read(int &x) {
int s=0;x=1;
char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')x=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
x*=s;
}
const int N=1e4+5;
int n, l;
double w;
PII e[N];
PDD q[N];
int main(){
while(cin>>n>>l>>w && n){
rep(i,1,n){
int a, b; read(a), read(b);
e[i]={b, a}; // radius and position
}
sort(e+1, e+1+n);
rep(i,1,n){
double o=e[i].y, r;
if(e[i].x<=w/2) r=0;
else r=sqrt(1.0*e[i].x*e[i].x-(1.0*w/2)*(w/2));
double L=max((double)0, o-r), R=min((double)l, o+r);
q[i]={L, R};
}
sort(q+1, q+1+n);
int res=0, p=1;
bool ok=true;
double cur=0;
while(cur<l){ // 只要控制区域的最右没有到达草坪的最右,就继续更新
double np=cur; // new point 记录控制区域右端点。
for(; p<=n && q[p].x<=cur; p++) np=max(np, q[p].y); // p 维护前缀点集的装置编号,np 从中更新最右点。
if(np==cur && cur<l){ // 如果np没有得到更新而且无法到达终点,无解。
ok=false;
break;
}
res++; // 更新答案
cur=np; // 更新控制区域
}
if(ok) cout<<res<<endl;
else puts("-1");
}
return 0;
}