P4525 【模板】自适应辛普森法1
题目描述
试计算积分$$\int_{R}^{L} \frac{cx+d}{ax+b}dx$$
结果保留至小数点后 $6$位。
数据保证计算过程中分母不为 $0$ 且积分能够收敛。
输入格式
一行,包含 $6$ 个实数 $a,b,c,d,L,R$。
输出格式
一行,积分值,保留至小数点后 $6$ 位。
样例数据
输入
1 2 3 4 5 6
输出
2.732937
分析
注意特判$a=0$的情况
法一(数学)
$$\int_{R}^{L} \frac{cx+d}{ax+b}dx \\=\int_{R}^{L}\frac{c}{a} \times \frac{\frac{ad-bc}{a}}{ax+b}dx\\=\int_{R}^{L}\frac{c}{a} dx \times \int_{R}^{L}\frac{\frac{ad-bc}{a}}{ax+b}dx\\=\frac{c}{a}x+\frac{ad-bc}{a}\times \frac{1}{a}ln\left | ax+b\right |+C\\=\frac{ad-bc}{a^2}ln\left | ax+b\right |+C$$
法二(自适应辛普森算法)
当前段直接代入公式求积分,再将当前段从中点分割成两段,把这两段再直接代入公式求积分。如果当前段的积分和分割成两段后的积分之和相差很小的话,就可以认为当前段和二次函数很相似了,不用再递归分割了,代入公式计算,否则递归分割
代码
数学
#include <bits/stdc++.h> #define Space putchar(' ') #define Enter puts("") #define MAXN 100010 #define int long long using namespace std; typedef long long ll; typedef double Db; inline ll Read() { ll Ans = 0; char Ch = getchar() , Las = ' '; while(!isdigit(Ch)) { Las = Ch; Ch = getchar(); } while(isdigit(Ch)) { Ans = (Ans << 3) + (Ans << 1) + Ch - '0'; Ch = getchar(); } if(Las == '-') Ans = -Ans; return Ans; } inline void Write(ll x) { if(x < 0) { x = -x; putchar('-'); } if(x >= 10) Write(x / 10); putchar(x % 10 + '0'); } Db a , b , c , d , L , R; inline Db F(Db x) { return ((a * d - b * c) / (a * a)) * log(fabs(a * x + b)) + (c / a) * x; } inline Db F2(Db x) { return c * x * x / (2 * b) + d * x / b; } signed main() { scanf("%lf%lf%lf%lf%lf%lf" , &a , &b , &c , &d , &L , &R); if(a != 0) printf("%.6lf" , F(R) - F(L)); else printf("%.6lf" , F2(R) - F2(L)); return 0; }
自适应辛普森
#include <bits/stdc++.h> #define Space putchar(' ') #define Enter puts("") #define MAXN 100010 #define int long long using namespace std; typedef long long ll; typedef double Db; inline ll Read() { ll Ans = 0; char Ch = getchar() , Las = ' '; while(!isdigit(Ch)) { Las = Ch; Ch = getchar(); } while(isdigit(Ch)) { Ans = (Ans << 3) + (Ans << 1) + Ch - '0'; Ch = getchar(); } if(Las == '-') Ans = -Ans; return Ans; } inline void Write(ll x) { if(x < 0) { x = -x; putchar('-'); } if(x >= 10) Write(x / 10); putchar(x % 10 + '0'); } Db a , b , c , d , L , R; Db eps = 0.0000001; inline double f(double x) { return (c*x+d)/(a*x+b); } double simpson(double l, double r) { double mid = (l + r) / 2; return (r - l) * (f(l) + 4 * f(mid) + f(r)) / 6; } double asr(double a,double b,double eps,double A){ double c=a+(b-a)/2; double L=simpson(a,c),R=simpson(c,b); if(fabs(L+R-A)<=15*eps) return L+R+(L+R-A)/15; else return asr(a,c,eps/2,L)+asr(c,b,eps/2,R); } signed 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; }