P4526 题解
FurippuWRY · · 题解
鲜花:刚做这道题的时候,自学乱学了
题意很清楚了,输入
观察函数图象,不断改变
关于这个 没有证明,我懒,而且我应该也不会证。(瞪眼法多好用啊。
做法如下:先套上辛普森公式:对于一个二次函数
诶这题的函数也不是二次函数啊咋求啊?
我们这样考虑:假如有一段图象已经很接近二次函数的话,直接带入公式求积分,得到的值精度就很高了,不需要再继续分割这一段了。
于是我们有了这样一种分割方法:每次判断当前段和二次函数的相似程度,如果足够相似的话就直接代入公式计算,否则将当前段分割成左右两段递归求解。
现在就剩下一个问题了:如果判断每一段和二次函数是否相似?
我们把当前段直接代入公式求积分,再将当前段从中点分割成两段,把这两段再直接代入公式求积分。如果当前段的积分和分割成两段后的积分之和相差很小的话,就可以认为当前段和二次函数很相似了,不用再递归分割了。——OI-Wiki
总之就是将函数分割成多个与二次函数图象相似的部分进行计算,递归求解。
double asr(double l, double r, double eps, double ans, int step) {
double mid = (l + r) / 2;
double fl = simpson(l, mid), fr = simpson(mid, r);
if (abs(fl + fr - ans) <= 15 * eps && step < 0)
return fl + fr + (fl + fr - ans) / 15;
return asr(l, mid, eps / 2, fl, step - 1) + asr(mid, r, eps / 2, fr, step - 1);
}
code
那坨辛普森函数是 Copy 自 OI-Wiki 的,因为我懒得打。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
double a;
double f(double x) {
return pow(x, a / x - x);
}
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 l, double r, double eps, double ans, int step) {
double mid = (l + r) / 2;
double fl = simpson(l, mid), fr = simpson(mid, r);
if (abs(fl + fr - ans) <= 15 * eps && step < 0)
return fl + fr + (fl + fr - ans) / 15;
return asr(l, mid, eps / 2, fl, step - 1) + asr(mid, r, eps / 2, fr, step - 1);
}
double calc(double l, double r, double eps) {
return asr(l, r, eps, simpson(l, r), 12);
}
void solve() {
if (a < 0) puts("orz");
else printf("%.5lf",calc(1e-10, 20, simpson(1e-10, 20)));
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> a;
solve();
return 0;
}
对辛普森公式
设有函数
则有
其中
所以