从零开始刷HDOJ(3)【HDOJ2899 – Strange function 】
题面
Strange fuction
Time limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 7321 Accepted Submission(s): 5057
Problem Description
Now, here is a function:
F(x)=6x7+8x6+7x3+5x2−yx(0≤x≤100)
Can you find the minimum value when x is between 0 and 100.
Input
The first line of the input contains an integer T(1<=T<=100) which means the number of test cases. Then T lines follow, each line has only one real numbers Y.(0 < Y <1e10)
Output
Just the minimum value (accurate up to 4 decimal places),when x is between 0 and 100.
Sample Input
2
100
200
Sample Output
-74.4291 -178.8534
提交传送门:Submit
翻译
就是把求一下当 y 等于你输入的值时 F(x) 在[0, 100]上的零点。
思路
其实这个函数在[0, 100]上是单峯的。
Proof:
∵(kxμ)′=kμ(x)(μ−1)
∴F′(x)=42x6+48x5+21x2+10x–y
∵y=ax6在[0,100]上单调增,y=ax5在[0,100]上单调增,y=ax2在[0,100]上单调增,y=ax在[0,100]上单调增
∴F′(x)在[0,100]上单调增
既然我们可以证明 F(x) 的导函数 F′(x) 在定义域单调增,那么我们就可以在定义域中二分零点(具体方法参考高中数学必修一),找到的这个点就是我们要求的取值点了。最后输出 F(ans) 就好了。
代码
#include <cmath>
#include <iostream>
// F(x) = 6x7 + 8x6 + 7x3 + 5x2 – xy
double y;
inline double f(const double x)
{
return 6 * std::pow(x, 7) + 8 * std::pow(x, 6) + 7 * std::pow(x, 3) + 5 * std::pow(x, 2) - y * x;
}
inline double F(const double x)
{
return 42 * std::pow(x, 6) + 48 * std::pow(x, 5) + 21 * std::pow(x, 2) + 10 * x;
}
int main(int argc, char ** argv)
{
std::ios_base::sync_with_stdio(false);
std::cout.setf(std::ios_base::fixed);
std::cout.precision(4);
double ans;
double l = 0.0, r = 100.0;
int times = 1000;
int T;
std::cin >> T;
while (T--)
{
std::cin >> y;
l = 0.0;
r = 100.0;
times = 10000;
double eps = 1e-10;
while (times--)
{
double mid = (l + r) / 2.0;
if (F(mid)>y)
r = mid;
else
l = mid;
}
std::cout << f(l) << std::endl;
}
std::cin.get();
std::cin.get();
return 0;
}