這道題要用帶一點點三角函數。。。
不用怕,只要有理性的思維,是可以知道怎麼做的
度娘!
說說我對三角函數的理解吧,簡單來說,就是如果你知道直角三角形的一個銳角,那你就知道了這個直角三角型的形狀了(求出三個角的角度數),那麼如果由另一個直角三角型的三個角也跟這個三角形相等,那麼他們兩個是可以通過比例轉化的,他們三條邊中任意兩條邊之比也相等(也就是任意兩條邊之比如果角的度數固定了,那麼這倆條邊的比就固定了)。
安利:
那麼,假設人的影子沒有在牆上,那麼,人從燈底往右走,走越遠影子越長!那麼最長的情況就是這樣:
由於比相同,設影長爲L,設人離燈x米遠。
那麼我們得出了,在影子全在地上,L的最大值爲Dh/H,這時x爲D-Dh/H,設left=D-Dh/H
那麼,如果影子全在牆上,則L=h,x=D,設right爲D。
如果影子在牆上,就比較抽象了。。。
然後呢。。。?
那麼:
那麼在牆上的影子就是
那麼就是要讓取最小值,可以證明,在正數區間,是個開口向上的單峯函數。
證:
情況1:x增加y,減小的數大於y
情況2:x增加y,減小的數小於y
又由於x越大,/x減小的數字越小,所以,會由情況1慢慢轉爲情況2,於是便由下降變爲上升,成單峯勢。
於是,便是個開口向下的單峯函數!(那你整這麼一大坨有什麼用?)
早說有圖片!
實現:
l=left,r=right;
當答案=l時,代表影子全在地上的最大值。
當答案=r是時,代表影子全在牆上的最大值。
當答案=(l,r)時,代表影子一半在牆上,一半在地上的最大值。
代碼:
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
inline double mymax(double x,double y){return x>y?x:y;}
inline double cai(double H,double h,double D,ll x)
{
double xx=x/10000.0;
return H+D-xx-((H-h)*D)/xx;
}//之前推出的函數
double sanfen(double H,double h,double D)
{
ll l=ll((D-(h*D)/H)*10000.0),r=ll(D*10000.0);//乘以10000轉ll
ll m1,m2;
while(l<r)//三分
{
m1=(l+r)/2;m2=(l+r)/2+1;
if(cai(H,h,D,m1)>cai(H,h,D,m2))r=m1;
else l=m2;
}
return cai(H,h,D,l);//真象只有一個,l或r就是答案
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
double H,h,D;scanf("%lf%lf%lf",&H,&h,&D);
printf("%.3lf\n",sanfen(H,h,D));//輸出
}
return 0;
}
公式法:
因爲這個我看了好久題解(淚奔)(:光速逃
那麼,如果是經驗豐富的巨佬,一定會想到公式法。。。
那是不是代表~~證出來了,耶!~~想太多
安利:
那麼我們就可以名正言順說耶!
所以
所以,當等於時,位於單峯上,同時也位於單峯上
當然,當時,由於是個開口向下的單峯函數,且所以x=left。
同理當時,x=right!
代碼:
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int main()
{
int T;scanf("%d",&T);
while(T--)
{
double H,h,D;scanf("%lf%lf%lf",&H,&h,&D);
double x=sqrt((H-h)*D);
if(x<=D-(h*D)/H)printf("%.3lf\n",(h*D)/H);//全在地上
else if(x>=D)printf("%.3lf\n",h);//全在牆上
else printf("%.3lf\n",H+D-x*2);//一部分在地上,一部分在牆上
}
return 0;
}
光速逃,耶!寫完了!