自适应辛普森法题解与学习笔记
前言
首先看到P4525 【模板】自适应辛普森法 1。这题是很好的辛普森板题,但是用牛顿-莱布尼茨公式就可以算出答案:
当 a=0 时,
∫ax+bcx+ddx=∫bcx+ddx=b1(∫cxdx)+b1(∫ddx)=2bcx2+bdx
当 a=0 时,
∫ax+bcx+ddx=∫ax+bac(ax+b)−abc+ddx=(∫acdx)+((−abc+d)∫ax+b1dx)=acx+(d−abc)aln∣ax+b∣
虽然这样我们就可以通过这题,但是肯定还要讲一下自适应辛普森法。
算法介绍
Simpson 法的思想是将原曲线近似为一段段抛物线,再求每一段的面积。具体地,我们令 f(x)=ax+bcx+d,g(x)=Ax2+Bx+C 为拟合函数,则有
∫LRf(x)dx≈∫LRg(x)=3A(b3−a3)+2B(b2−a2)+C(b−a)=6b−a(Aa2+Ba+C+Ab2+Bb+C+A(b−a)2+2B(b−a)+4C)=6b−a(f(a)+f(b)+f(2b−a))
介绍完 Simpson 法后我们再回过头看这题。
题解
题目要求∫0∞xxa−xdx,肯定不能用牛顿-莱布尼茨公式。经过讨论可得:
当 a<0 时,limx→0xxa−x2=elimx→0xa−x2lnx=+∞ ,原函数发散,输出 orz。
当 a≥0 时。
limx→+∞x2xxa−x2=elimx→∞xa−x2+2xlnx=0 ,原函数收敛。用 Simpson 法解决即可。
cpp#include<bits/stdc++.h>
using namespace std;
const double eps=1e-10;
double a;
double f(double x){return pow(x,a/x-x);}
double Simpson(double l,double r){return (f(l)+f(r)+4*f((l+r)/2))*(r-l)/6;}
double Query(double l,double r,double t){
double mid=(l+r)/2,x=Simpson(l,mid),y=Simpson(mid,r);
if(fabs(x+y-t)<=1e-9)return t;
else return Query(l,mid,x)+Query(mid,r,y);
}
int main(){
cin>>a;
if(a<0)return cout<<"orz",0;
cout<<fixed<<setprecision(5)<<Query(eps,20,Simpson(eps,20));
}