二次函数的定积分

对于一个二次函数 图片说明 ,显然有 图片说明
对于一个奇怪的函数,为了对其求导,我们可以用一个图像近似且容易求导的函数(这里我们使用二次函数)来代替它(拟合),这样的话精度误差可能会很大,因此我们需要将函数分段拟合。

自适应辛普森法

显然我们并不知道分成多少段合适,因为段分得越多,精度误差越小,但时间消耗越大;段分得越少,精度误差越大,但时间消耗越小。

我们需要一个“自适应”的操作。

如果这一段函数与拟合的二次函数“相似”,那么我们直接把这一段当做这个二次函数,然后套用公式计算;如果这一段函数与拟合的二次函数“不相似”,那么我们应该把这一段分成两半,并递归进行这一过程。

接下来的问题就是,如何判断是否“相似”呢?

我们可以对整段、左半部分、右半部分分别套用二次函数定积分公式进行计算,结果分别记作 ans、lans 和 rans,若 lans + rans 与 ans 相差的值不超过我们设定的精度了,那么我们就认为这一段函数与拟合的二次函数是“相似”的。

#include<bits/stdc++.h> // https://www.luogu.com.cn/problem/P4525

using namespace std;

const double eps = 1e-6;

double a, b, c, d, L, R;

double f(double x) {
    return (c * x + d) / (a * x + b);
}

double simpson(double l, double r) {
    double mid = (l + r) / 2;
    return (f(l) + f(r) + 4 * f(mid)) * (r - l) / 6;
}

double asr(double l, double r, double ep, double ans) {
    double mid = (l + r) / 2;
    double lans = simpson(l, mid);
    double rans = simpson(mid, r);
    if (fabs(lans + rans - ans) <= 15 * ep)
        return lans + rans + (lans + rans - ans) / 15;
    return asr(l, mid, ep/2, lans) + asr(mid, r, ep/2, rans);
}

int main() {
    scanf("%lf%lf%lf%lf%lf%lf", &a, &b, &c, &d, &L, &R);
    printf("%.6f\n", asr(L, R, eps, simpson(L, R)));
    return 0;
}

常数优化

#include<bits/stdc++.h>  //https://www.luogu.com.cn/problem/P4526

using namespace std;

const double eps = 1e-8;

double a;

double f(double x) {
    return pow(x, a/x-x);
}

double simpson(double len, double fl, double fr, double fm) {
    return (fl + fr + 4 * fm) * len / 6;
}

double asr(double l, double r, double ep, double fl, double fr, double fm) {
    double len = r - l;
    double flm = f(l+len/4);
    double frm = f(r-len/4);
    double ans = simpson(len, fl, fr, fm);
    double lans = simpson(len/2, fl, fm, flm);
    double rans = simpson(len/2, fm, fr, frm);
    if (fabs(lans + rans - ans) <= 15 * ep)
        return lans + rans + (lans + rans - ans) / 15;
    return asr(l, l+len/2, ep/2, fl, fm, flm) + asr(l+len/2, r, ep/2, fm, fr, frm);
}

int main() {
    scanf("%lf", &a);
    if (a < 0) printf("orz\n");
    else printf("%.5f\n", asr(eps, 15, eps, f(eps), f(15), f((eps+15)/2)));
    return 0;
}

应用

求定积分

https://www.luogu.com.cn/problem/P4525 【第一类曲面积分】
https://www.luogu.com.cn/problem/P4526 【反常积分】