目录
题目描述
试计算积分
结果保留至小数点后 6 位。
数据保证计算过程中分母不为 0 且积分能够收敛。
输入格式
一行,包含 6 个实数 a,b,c,d,L,R。
输出格式
一行,积分值,保留至小数点后 6 位。
输入输出样例
输入 #1
1 2 3 4 5 6
输出 #1
2.732937
说明/提示
a,b,c,d∈[−10,10],−100≤L<R≤100 且 R−L≥1。
一、纯数学推导
①a 不等于 0
我们需要先判断 a 是否等于 0 ,如果不等于 0 ,那么:
1.变形
首先,我们可以把 变成 。为什么?
我们观察被积函数 ,为了更容易地积分,我们尝试将分子重写为与分母线性相关的形式加上一个常数项。具体来说,我们希望将分子 改写为 的形式,其中 k 和 m 是常数。
通过比较系数,我们可以得到:
展开并整理得:
由于两边的 x 和常数项的系数必须相等,我们可以列出方程组:
解这个方程组,我们得到:
因此,分子可以重写为:
即:
2.积分
我们再在上面的基础上进行积分:
(令 u = ax+b , du = a dx )
(代回 u = ax+b )
3.转化
我们最后来转化一下,使这个式子变成一个更加简洁的式子。
所以
②a 等于 0
如果 a 等于 0 的话, 就变成了 ,积分就可以简化为:
③代码
所以,代码是:
#include<bits/stdc++.h>
using namespace std;
double a,b,c,d,l,r;
double f1(double x)
{
return (c*x)/a+((a*d-b*c)/(a*a))*log(fabs(a*x+b));
}
double f2(double x)
{
return (c/(2*b))*x*x+(d/b)*x;
}
int main() {
cin>>a>>b>>c>>d>>l>>r;
if(a==0.0)
{
printf("%.6f",f2(r)-f2(l));
}
else
{
printf("%.6f",f1(r)-f1(l));
}
return 0;
}
二、自适应辛普森法
当然,这道题可以用自适应辛普森法去做。
1.思路
自适应辛普森算法是一类近似算法,主要用于求较难反导的函数的积分。其思想是利用二次函数曲线来不断拟合所求曲线。而自适应则是用于优化时间复杂度的方法。
什么是拟合?
如果给定了一个函数,我们可以用一个图像与它近似的初等函数来代替它,这样的过程称之为“拟合”。
辛普森公式
辛普森公式推导
对于一个二次函数 ,求积分可得:
那么:
我们可以用辛普森公式去求定积分。我们把积分区间分成很多的非常小的区间,每一个区间,我们都拟合一下。
关键是我们要分成多少段?
如果我们分得太少了,答案就会不精确;如果我们分得太多了,时间会太长。
所以,关键就是“自适应”。精度不够低,我们就再继续分;精度够了,我们就不再分下去了。核心过程就是,递归二分划分区间,精度达到标准,终止递归。否则继续递归。
模板:
const double eps=精度要求;
double f(double x)
{
需要积分的函数
}
double simpson(double l,double r)
{
return (r-l)*(f(r)+f(l)+4.0*f((l+r)/2))/6;
}
double answer(double l,double r,double ans)
{
double mid=(l+r)*0.5;
double fl=simpson(l,mid);
double fr=simpson(mid,r);
if(fabs(fl+fr-ans)<=eps)
{
return fl+fr;
}
else
{
return answer(l,mid,fl)+answer(mid,r,fr);
}
}
2.代码
#include<bits/stdc++.h>
using namespace std;
double a,b,c,d,l,r;
double eps=1e-12;
double f(double x)
{
return (c*x+d)/(a*x+b);
}
double simpson(double l,double r)
{
return (r-l)*(f(r)+f(l)+4.0*f((l+r)/2))/6;
}
double answer(double l,double r,double ans)
{
double mid=(l+r)*0.5;
double fl=simpson(l,mid);
double fr=simpson(mid,r);
if(fabs(fl+fr-ans)<=eps)
{
return fl+fr;
}
else
{
return answer(l,mid,fl)+answer(mid,r,fr);
}
}
int main()
{
cin>>a>>b>>c>>d>>l>>r;
printf("%.6f",answer(l,r,simpson(l,r)));
return 0;
}