并没想打算开篇小小结,只是随便写写(感觉开小小结的成本太高了啊……)
感觉还是挺妙的。以前听zyy 大佬讲课的时候说过,函数的积分用二次函数拟合一下。
加入我们要算 ∫𝑟𝑙𝐹(𝑥)d𝑥,我们用二次函数 𝑓(𝑥)=𝑎𝑥2+𝑏𝑥+𝑐 来拟合。
我们发现:
∫𝑟𝑙𝑓(𝑥)d𝑥=𝑎3𝑟3+𝑏2𝑟2+𝑐𝑟−𝑎3𝑙3−𝑏2𝑙2−𝑐𝑙=𝑎3(𝑟−𝑙)(𝑟2+𝑙2+𝑙𝑟)+𝑏2(𝑟−𝑙)(𝑟+𝑙)+𝑐(𝑟−𝑙)=𝑟−𝑙6(2𝑎𝑟2+2𝑎𝑙2+2𝑎𝑙𝑟+3𝑏𝑟+3𝑏𝑙+6𝑐)=𝑟−𝑙6(𝑎𝑟2+𝑏𝑟+𝑐+𝑎𝑙2+𝑏𝑙+𝑐+𝑎𝑟2+𝑎𝑙2+2𝑎𝑙𝑟+2𝑏𝑟+2𝑏𝑙+4𝑐)=𝑟−𝑙6(𝑓(𝑙)+𝑓(𝑟)+𝑎(𝑙+𝑟)2+2𝑏(𝑙+𝑟)+4𝑐)=𝑟−𝑙6(𝑓(𝑙)+𝑓(𝑟)+4(𝑎(𝑙+𝑟2)2+𝑏(𝑙+𝑟2)+𝑐))=𝑟−𝑙6(𝑓(𝑙)+𝑓(𝑟)+4𝑓(𝑙+𝑟2))
于是我们有:
∫𝑟𝑙𝐹(𝑥)d𝑥≈𝑟−𝑙6(𝐹(𝑙)+𝐹(𝑟)+4𝐹(𝑙+𝑟2))
然后就可以拟合辣!
inline double simpson(double l, double r)
{
return (F(l) + F(r) + 4 * F((l + r) / 2)) * (r - l) / 6;
}
然而就是要么 WA(炸精度)要么 T……
有一种叫自适应辛普森的方法解决这个问题,我们用辛普森计算 ∫𝑟𝑙𝐹(𝑥)d𝑥,∫(𝑙+𝑟)/2𝑙𝐹(𝑥)d𝑥,∫𝑟(𝑙+𝑟)/2𝐹(𝑥)d𝑥 的值,如果
∣∫𝑟𝑙𝐹(𝑥)d𝑥−(∫(𝑙+𝑟)/2𝑙𝐹(𝑥)d𝑥+∫𝑟(𝑙+𝑟)/2𝐹(𝑥)d𝑥)∣≤eps
那么直接返回值,否则递归下去算。
upd:忽然发现我学了个假的 simpson。其实 eps 应该是相对误差,所以每次递归下去时 eps 都应该除 2。听说最后判定时应该是 ≤15⋅eps,虽然我并不知道是为什么。话说这和 eps 乘上 15 有什么区别吗
这样复杂度就是 O(玄学),交之前洗把脸就行了。
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);
}