并没想打算开篇小小结,只是随便写写(感觉开小小结的成本太高了啊……)
感觉还是挺妙的。以前听 zyy 大佬 讲课的时候说过,函数的积分用二次函数拟合一下。
加入我们要算 ∫lrF(x)dx,我们用二次函数f(x)=ax2+bx+c 来拟合。
我们发现:
∫lrf(x)dx=3ar3+2br2+cr−3al3−2bl2−cl=3a(r−l)(r2+l2+lr)+2b(r−l)(r+l)+c(r−l)=6r−l(2ar2+2al2+2alr+3br+3bl+6c)=6r−l(ar2+br+c+al2+bl+c+ar2+al2+2alr+2br+2bl+4c)=6r−l(f(l)+f(r)+a(l+r)2+2b(l+r)+4c)=6r−l(f(l)+f(r)+4(a(2l+r)2+b(2l+r)+c))=6r−l(f(l)+f(r)+4f(2l+r))
于是我们有:
∫lrF(x)dx≈6r−l(F(l)+F(r)+4F(2l+r))
然后就可以拟合辣!
1 2 3 4
| inline double simpson(double l, double r) { return (F(l) + F(r) + 4 * F((l + r) / 2)) * (r - l) / 6; }
|
然而就是要么 WA(炸精度)要么 T……
有一种叫自适应辛普森的方法解决这个问题,我们用辛普森计算 ∫lrF(x)dx,∫l(l+r)/2F(x)dx,∫(l+r)/2rF(x)dx 的值,如果∣∣∣∣∫lrF(x)dx−(∫l(l+r)/2F(x)dx+∫(l+r)/2rF(x)dx)∣∣∣∣≤eps,那么直接返回值,否则递归下去算。
upd:忽然发现我学了个假的 simpson
。其实eps
应该是相对误差,所以每次递归下去时 eps 都应该除 2。听说最后判定时应该是≤15⋅eps,虽然我并不知道是为什么。 话说这和 eps 乘上 15 有什么区别吗
这样复杂度就是 O( 玄学),交之前洗把脸就行了。
1 2 3 4 5 6 7 8
| inline double asr(double l, double r, double ans, double eps) { double mid = (l + r) * .5; double ll = simpson(l, mid), rr = simpson(mid, r); if(fabs(ll + rr - ans) < 15 * eps) return ll + rr; return asr(l, mid, ll, eps * .5) + asr(mid, r, rr, eps * .5); }
|