[hdu4498]离散化,simpson求积分
题意:,求这个函数在[0,100]上的图像的长度。
思路:采用离散化的思想,求出所有交点 ,把交点排序,把[0,100]分成若干个小区间,这样原函数在每个小区间上的图像属于某一个二次函数或者是一条直线。如何确定属于哪个呢?比如对于某个区间,令m为这个小区间的中点,求出所有的函数在m点的函数值的最小值,对应的那个函数就是答案。如果最小值>=100则说明是直线。那么问题就变成了求二次函数曲线在区间[L,R]上的长度。这个可以转化为积分来算,令f(x)为原函数的倒数,则答案就是sqrt(1+f(x)*f(x))在[L,R]上的积分了。求积分可以用自适应辛普森法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <queue> #include <cmath> #include <algorithm> using namespace std; const int maxn = 123; #define _x2(a) (a) * (a) namespace Integral { double (*func)( double ); double simpson( double a, double b) { double c = a + (b - a) / 2; return (func(a) + func(c) * 4 + func(b)) * (b - a) / 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; return asr(a, c, eps / 2, L) + asr(c, b, eps / 2, R); } double getans( double a, double b, double eps, double (*f)( double )) { func = f; return asr(a, b, eps, simpson(a, b)); } }; int k[maxn], a[maxn], b[maxn]; int A[maxn], B[maxn], C[maxn]; int ga, gb, gc, cnt; double pos[12345]; double F( double x) { return ga * x * x + gb * x + gc; } double f( double x) { return sqrt (1.0 + _x2(2.0 * ga * x + gb)); } void add( double x) { if (x > 0 && x < 100) pos[cnt ++] = x; } int main() { #ifndef ONLINE_JUDGE freopen ( "in.txt" , "r" , stdin); #endif // ONLINE_JUDGE int T, n; cin >> T; while (T --) { cnt = 0; pos[cnt ++] = 0; pos[cnt ++] = 100; cin >> n; for ( int i = 0; i < n; i ++) { cin >> k[i] >> a[i] >> b[i]; A[i] = k[i]; B[i] = -2 * k[i] * a[i]; C[i] = k[i] * a[i] * a[i] + b[i]; if (b[i] < 100) { double buf = sqrt ((100.0 - b[i]) / k[i]); add(a[i] + buf); add(a[i] - buf); } } for ( int i = 0; i < n; i ++) { for ( int j = i + 1; j < n; j ++) { ga = A[i] - A[j]; gb = B[i] - B[j]; gc = C[i] - C[j]; if (ga == 0) { if (gb != 0) add(-1.0 * gc / gb); continue ; } int d = gb * gb - 4 * ga * gc; if (d >= 0) { add((-gb - sqrt (1.0 * d)) / 2.0 / ga); if (d) add((-gb + sqrt (1.0 * d)) / 2.0 / ga); } } } sort(pos, pos + cnt); double ans = 0; for ( int i = 1; i < cnt; i ++) { double L = pos[i - 1], R = pos[i]; if (R - L < 1e-10) continue ; double M = (L + R) / 2, minval = 100; int target = -1; for ( int i = 0; i < n; i ++) { ga = A[i]; gb = B[i]; gc = C[i]; if (F(M) < minval) { minval = F(M); target = i; } } if (~target) { ga = A[target]; gb = B[target]; gc = C[target]; ans += Integral::getans(L, R, 1e-8, f); } else ans += R - L; } printf ( "%.2f\n" , ans); } return 0; } |