Luogu4525【模板】自适应辛普森法1

Luogu4525【模板】自适应辛普森法1

题面:洛谷

解析

讲一讲这东西吧。

自适应辛普森法的原理就是用二次函数来拟合所给函数,然后计算二次函数的积分得到近似答案,这里首先给出二次函数的积分公式(也就是所谓的辛普森公式)并证明。

\[=\int_{l}^{r} F(x){ \rm d}x \]

\[=\int_{l}^{r} (ax^2+bx+c){\rm 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 \times ar^3 +3 \times br^2 +6r-2 \times al^3 -3 \times 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+4b\frac{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\n",asr(L,R));
    return 0;
}


posted @ 2019-03-15 22:06  pkh68  阅读(266)  评论(0编辑  收藏  举报