3074. 自适应辛普森积分
题目链接
3074. 自适应辛普森积分
给定两个整数 \(a,b\),请计算如下积分:
\(\int_a^b \frac{Sin(x)}{x}dx\)
输入格式
共一行,包含两个实数 \(a,b\)。
输出格式
输出一个实数,表示结果。
结果保留 \(6\) 位小数。
数据范围
\(1 \le a < b \le 100\)
输入样例:
1.0 2.0
输出样例:
0.659330
解题思路
自适应辛普森积分
辛普森积分主要用来求解任意一个连续函数在一段区间的积分(面积),类似于微积分的定义,即将区间分为很多微小的小段,将区间的高假定为某个值,然后用矩形的面积取代该段不规则的形状的面积,而辛普森积分则是用一个二次函数近似小段的曲线,其用到一个求解一次二次函数某个区间 \([l,r]\) 的面积公式:\(S=(r-l)\times \frac{f(l)+4\times f(mid)+f(r)}{6}\)
而自适应辛普森积分则是先用面积公式求出 \([l,r]\) 内的面积 \(S\),再分别求出左、右半边的面积 \(S_l,S_r\),然后拿 \(S\) 和 \(S_l+S_r\) 进行比较,如果其误差在允许的范围内说明该值可取,否则递归处理左右半边
自适应辛普森积分主要处理一些精度要求不高的问题,而且要求函数低阶
- 时间复杂度:\((玄学)\)
代码
// Problem: 自适应辛普森积分
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/3077/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const double eps=1e-12;
double l,r;
double f(double x)
{
return sin(x)/x;
}
double simpson(double l,double r)
{
double mid=(l+r)/2;
return (f(l)+f(mid)*4+f(r))/6*(r-l);
}
double asr(double l,double r,double s)
{
double mid=(l+r)/2;
double L=simpson(l,mid),R=simpson(mid,r);
if(fabs(s-L-R)<eps)return L+R;
return asr(l,mid,L)+asr(mid,r,R);
}
int main()
{
scanf("%lf%lf",&l,&r);
printf("%.6lf",asr(l,r,simpson(l,r)));
return 0;
}