Luogu4525【模板】自适应辛普森法1
题面:洛谷
解析
讲一讲这东西吧。
自适应辛普森法的原理就是用二次函数来拟合所给函数,然后计算二次函数的积分得到近似答案,这里首先给出二次函数的积分公式(也就是所谓的辛普森公式)并证明。
[=int_{l}^{r} F(x){
m d}x
]
[=int_{l}^{r} (ax^2+bx+c){
m d}x
]
[=frac{a}{3}r^3+frac{b}{2}r^2+cr-frac{a}{3}l^3-frac{b}{2}l^2-cl
]
[=frac{2 imes ar^3 +3 imes br^2 +6r-2 imes al^3 -3 imes bl^2 -6l}{6}
]
[=(r-l)frac{2a(r^2+rl+l^2)+3b(r+l)+6c}{6}
]
[=(r-l)frac{ar^2+br+c+al^2+bl+c+4a(frac{r+l}{2})^2+4bfrac{r+l}{2}+4c}{6}
]
[=(r-l)frac{F(l)+F(r)+4F(mid)}{6}
]
然后它的思想是尽量用这个公式去计算积分,但是由于精度,所以要分段计算,容易计算的少分段,难以计算的多分段。如何判断呢?分别计算左右两部的积分加起来与当前积分比较就行了,具体实现请看代码。
代码
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-7;
double a,b,c,d,L,R;
inline double F(double x){ return (c*x+d)/(a*x+b); }
inline double simpson(double l,double r){
double a=F(l),b=F(r),c=F((l+r)/2.0);
return (r-l)*(a+b+4*c)/6.0;
}
inline double asr(double l,double r,double A){
double mid=(l+r)/2.0,L=simpson(l,mid),R=simpson(mid,r);
if(fabs(L+R-A)<=15*eps) return L+R+(L+R-A)/15.0;
else return asr(l,mid,L)+asr(mid,r,R);
}
inline double asr(double L,double R){ return asr(L,R,simpson(L,R)); }
int main(){
scanf("%lf%lf%lf%lf%lf%lf",&a,&b,&c,&d,&L,&R);
printf("%.6lf
",asr(L,R));
return 0;
}