明明保存了,却奇怪的消失了,真令人迷惑,只好再写一遍。
题目链接:P3382 【模板】三分法
我们知道极值处导函数值为(0),那么我们把这个函数的导数求出来,二分答案即可。
刚刚学习了导数,来看一下与这题有关的导数法则。
[[f(x)pm g(x)]'=f'(x)pm g'(x)
]
那我们推导到更多加减法的求导,对于一个(n)次多项式(f(x)):
[f(x)=sumlimits_{i=0}^na_ix^i
]
显然,它的导数是:
[f'(x)=sumlimits_{i=0}^{n-1}(i+1)a_{i+1}x^i
]
这个直接模拟就好了。
关于多项式的求值
对于高次项,容易想到对自变量(x)快速幂,不过这样是(mathcal O(nlog n))的,有没有更好的方法呢?
有!
早在很早以前,中国数学家秦九韶就提出了秦九韶算法,我们来举个栗子吧。
有一个多项式(g(x)):
[g(x)=ax^3+bx^2+cx+d
]
我们这样化简一下:
[g(x)=x(x(xa+b)+c)+d
]
这样就能(mathcal O(n))了。
double f(double g,int n)//求n次多项式f(g)的值
{
double x=fuc[n];
for(int i=1;i<=n;i++) x=g*x+fuc[n-i];
return x;
}
自己的想法
在讲述秦九韶算法时,莫名发现一种奇妙算法:
快速幂为什么慢呢?
显然是重复处理了一些幂次,那我们直接暴算幂次即可,这样也是(mathcal O(n))的:
double f(double g,double n)
{
double x=1,ans=0;
for(int i=0;i<=n;i++) ans=ans+x*fuc[i],x*=g;
return ans;
}
然后这道题就做完了:
(Code):
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define read(x) scanf("%d",&x)
#define read_d(x) scanf("%lf",&x)
double fuc[20];
double a[20];
int n;
double l,r;
double f(double g,int n)
{
double x=fuc[n];
for(int i=1;i<=n;i++) x=g*x+fuc[n-i];
return x;
}
int main()
{
read(n),read_d(l),read_d(r);
for(int i=n;i>=0;i--) read_d(a[i]);
//求导
for(int i=n;i>=1;i--) fuc[i-1]=a[i]*i;
double mid;
for(int i=1;i<=100;i++)
{
mid=(l+r)/2;
if(f(mid,n-1)<0) r=mid;
else l=mid;
}
printf("%.5lf
",mid);
return 0;
}
那么你如果对于多项式函数的求导一般式一脸懵逼,那么直接按定义做就好了:
我们知道导数的定义为:
[f'(x)=limlimits_{mathitDelta x
ightarrow 0}dfrac{f(x+mathitDelta x)-f(x)}{mathitDelta x}
]
我们可以把(mathitDelta x)设成很小的数如(10^{-10}),然后就行了。
大佬是这样做的,我来搬运代码:
(Code):
#include <bits/stdc++.h>
using namespace std;
const int N = 15;
const double eps = 1e-10;;
int n;
double L, R, a[N];
double f(double x) {
double c[N];
c[n] = a[n];
for (int i = n - 1; i >= 0; --i) c[i] = c[i + 1] * x + a[i];
return c[0];
}
double check(double x) {
double dx = eps;
double dy = f(x + eps) - f(x);
return dy / dx;
}
int main() {
cin >> n >> L >> R;
for (int i = 0; i <= n; ++i) cin >> a[n - i];
double mid;
while (R - L > eps) {
mid = (L + R) / 2;
if (check(mid) > 0) L = mid;
else R = mid;
}
printf("%.5lf", L);
return 0;
}
关于复杂度:
二分(100)次的话就是(mathcal O(100n))了,或者写成(
mathcal O(nlog eps))。
(ps):我自己(yy)的竟然比秦九韶算法快(8;ms)!