题目1
篮球判定问题
一个篮球会按照 一个二次函数 的轨迹进行运动
给出篮球框和篮板的坐标
如果篮球触碰到篮板会立马将X轴上的速度反向
问是否篮球能在从上面 向下并且不触碰篮球框边缘的 通过篮球框
如果可以输出 yes
否则输出no
此题可以分成两种情况
第一种是篮球没有触碰到篮板
那么直接运用零点定理
只需要 把篮球框 两个端点的坐标X坐标带入篮球的轨迹函数中
带入x0时
大于y0 (篮球框左端点y坐标)
带入x1时
小于y0(篮球框右端点 y坐标)
即可判定篮球通过了篮球框
第二种是篮球触碰到了篮板
这一种情况我当时怎么都没想出来应该怎么处理
后来突然想到,只要在篮板右侧,做一条 关于篮板的 篮球框的对称图形
这样,新的篮球框 坐标就变成了(x1,y0) (2x1-x0,y0)
虽然X轴的运动方向反向了,但是我们通过对称的方法,又把函数图像转移回来了。
此时我们要判断两个条件
第一是 篮球一定经过 篮板的上半部分
第二是 篮球一定经过 新篮框
所以再用零点定理
带入x1坐标,得到的值要大于y0小于等于y2 (篮球打在上篮板上)
带入 x0时 ,得到的值要大于 y0
带入 2x1-x0时,得到的值要小于 y0
(表示篮球经过了新篮框)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll f(ll a,ll b,ll c,ll x){//投篮的二次函数!
return a*x*x+b*x+c;
}
void solve() {
ll a,b,c;
cin>>a>>b>>c;
ll x0,x1,y0,y1,y2;
cin>>x0>>x1>>y0>>y1>>y2;
if(f(a,b,c,x0)>y0&&f(a,b,c,x1)<y0) {// 没有打在篮板上的情况!!!! 篮筐(x0,y0) (x1,y0)
//篮板 (x1,y1) (x1,y2)
cout<<"Yes"<<endl;
} else if(f(a,b,c,x1)>y0&&f(a,b,c,x0)>y0&&f(a,b,c,x1)<=y2&&f(a,b,c,2*x1-x0)<y0) {//本题关键!
//如果打在篮板上的话,X轴上的速度回发生反向!
//如果打在篮板上的话!
cout<<"Yes"<<endl;
} else {
cout<<"No"<<endl;
}
}
int main(){
ll r;
scanf("%lld",&r);
while(r--) {
solve();
}
return 0;
}
题目2
斜率最大值问题
现在已知函数上有N个点
给出每个点的 的横坐标 x 和函数值 f(x)
定义 |f(x)−f(y)|≤L⋅|x−y|
求出常数L的最大值
起初我还是很懵的
双for循环枚举每两个点,求L,然后取最大值
超时了
但是后来我发现,这个L其实就是函数 的 斜率
数学知识:
当一个函数中的两个点非常(极限)接近时,斜率就是最大的
所以我们只需要把每个点,按照 x 坐标进行排序
然后用排序之后的每两个相邻的点,计算L,再取最大即可!
#include<bits/stdc++.h>
using namespace std;
struct Stu
{
double x,y;
}stu[200001];
bool cmp(Stu x,Stu y)
{
return x.x<y.x;
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>stu[i].x;
cin>>stu[i].y;
}
sort(stu+1,stu+1+n,cmp);
double ans=-1e7;
for(int i=2;i<=n;i++)
{
double haha=fabs(stu[i].y-stu[i-1].y)/fabs(stu[i].x-stu[i-1].x);
ans=max(ans,haha);
}
printf("%.5lf",ans);
return 0;
}