题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3763
虽然题目有点长,但是仔细读下来发现也没什么。。。
给一个关于 t 的分段函数R(t):
When 0 ≤ t ≤ T, R(t) = c*t
When T < t ≤ T*2, R(t) = c * (T * 2 - t).
然后对于每个点(xi,yi),有一个速度(vx,vy)那么这个点在t时刻到点(x0,y0)的距离用d(t)表示。
题目就要求多少个点使得R(t)=d(t)在[0,2T]这个区间上有解。
由于d(t)直接表示带有根号,有点麻烦,所以我直接用d(t)和R(t)的平方来计算,下面用到的全部都是平方后的形式。
令F(t) = d(t)-R(t)
当0<=t<=T时,将已知的信息代入到F(t) 中可以得到(这个在纸上算下就行,我就不在这里展开了):
F(t) = A*t^2 + B*t +C
其中:A = vx*vx + vy*vy - c*c
B = 2*((x-x0)*vx + (y-y0)*vy)
C = (x-x0)^2 + (y-y0)^2
然后就是判断在[0,T]上是否有F(t)=0了,这个高中数学都学过了,找到区间的两个最值,看它们是否异号就行了。
至于最值,根据A如果是正的,说明可以求最小值,否则求最大值,剩下的最值在两个区间端点找就行了。
这里不用管在这个区间上二次函数长什么样,甚至它是不是二次都可以不用管,因为采用三分法计算最值的时候,单调的函数可以看作一种特例。
然后对于区间(T,2*T],方法跟上面类似,只是这个时候B要加上4*T*c*c,C要减去4*T*T*c*c,因为此时R(t)的公式不一样了。
PS:一开始很SB地在A是正的情况下求最大值,WA了很多次才发现这个已经不知道怎么形容的错误了。差点想开JAVA写高精了 = =
#include<cstdio>
const double eps = 1e-8;
double x0, y0, c, T;
int n;
double x, y, vx, vy;
double A, B, C;
double F(double t){
return A*t*t+B*t+C;
}
bool ok_min(double L, double R){
double low=L, top=R, m1, m2;
double s1, s2, s3;
while(top-low>eps){
m1 = low+(top-low)/3.0;
m2 = top-(top-low)/3.0;
s1 = F(m1);
s2 = F(m2);
if(s1<s2) top = m2-eps;
else low = m1+eps;
}
s1 = F(L);
s2 = F(R);
s3 = F(low);
if(s1*s3<eps || s2*s3<eps || s1*s2<eps) return 1;
else return 0;
}
bool ok_max(double L, double R){
double low=L, top=R, m1, m2;
double s1, s2, s3;
while(top-low>eps){
m1 = low+(top-low)/3.0;
m2 = top-(top-low)/3.0;
s1 = F(m1);
s2 = F(m2);
if(s1<s2) low = m1+eps;
else top = m2-eps;
}
s1 = F(L);
s2 = F(R);
s3 = F(low);
if(s1*s3<eps || s2*s3<eps || s1*s2<eps) return 1;
else return 0;
}
int check(){
A = vx*vx+vy*vy-c*c;
B = 2.0*((x-x0)*vx+(y-y0)*vy);
C = (x-x0)*(x-x0)+(y-y0)*(y-y0);
if(A<=0){
if(ok_max(0,T)) return 1;
}
else{
if(ok_min(0,T)) return 1;
}
B += 4.0*T*c*c;
C -= 4.0*T*T*c*c;
if(A<=0){
if(ok_max(T,T*2)) return 1;
}
else{
if(ok_min(T,T*2)) return 1;
}
return 0;
}
int main(){
while(~scanf("%lf %lf %lf %lf", &x0, &y0, &c, &T)){
scanf("%d", &n);
int ans=0;
while(n--){
scanf("%lf %lf %lf %lf", &x, &y, &vx, &vy);
ans += check();
}
printf("%d\n", ans);
}
return 0;
}