https://coderun.yandex.ru/problem/area-between-curves Средняя

Решение

import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import kotlin.math.sqrt
import kotlin.math.abs
import kotlin.math.min

fun main(args: Array<String>) {
    val reader = BufferedReader(InputStreamReader(System.`in`))
    val writer = BufferedWriter(OutputStreamWriter(System.out))
    
    // Считываем количество частей для f и g.
    val line = reader.readLine().split(" ")
    val n = line[0].toInt()  // число участков для f
    val m = line[1].toInt()  // число участков для g
    
    // Считываем границы для функции f (n+1 чисел)
    val fBoundaries = reader.readLine().split(" ").map { it.toDouble() }.toDoubleArray()
    // Считываем n строк с коэффициентами полинома для f: a, b, c (f(x)=a*x^2+b*x+c)
    val fA = DoubleArray(n)
    val fB = DoubleArray(n)
    val fC = DoubleArray(n)
    for (i in 0 until n) {
        val parts = reader.readLine().split(" ")
        fA[i] = parts[0].toDouble()
        fB[i] = parts[1].toDouble()
        fC[i] = parts[2].toDouble()
    }
    
    // Считываем границы для функции g (m+1 чисел)
    val gBoundaries = reader.readLine().split(" ").map { it.toDouble() }.toDoubleArray()
    // Считываем m строк с коэффициентами полинома для g.
    val gA = DoubleArray(m)
    val gB = DoubleArray(m)
    val gC = DoubleArray(m)
    for (i in 0 until m) {
        val parts = reader.readLine().split(" ")
        gA[i] = parts[0].toDouble()
        gB[i] = parts[1].toDouble()
        gC[i] = parts[2].toDouble()
    }
    
    // Общая область интегрирования [L0, L_end] – гарантировано, что fBoundaries[0]=gBoundaries[0] и fBoundaries[n]=gBoundaries[m].
    val L0 = fBoundaries[0]
    val Lend = fBoundaries[n]
    
    var totalArea = 0.0
    var i = 0  // индекс для f
    var j = 0  // индекс для g
    var currentX = L0
    val eps = 1e-12
    // Выполняем двухуказательный проход по промежуткам
    while (currentX < Lend - eps && i < n && j < m) {
        // Следующая граница – минимум следующей границы у f и у g.
        val nextX = min(fBoundaries[i+1], gBoundaries[j+1])
        // На данном интервале:
        // f(x)= fA[i]*x^2 + fB[i]*x + fC[i],
        // g(x)= gA[j]*x^2 + gB[j]*x + gC[j].
        // Пусть p(x)= f(x)-g(x)= A*x^2 + B*x + C.
        val A = fA[i] - gA[j]
        val B = fB[i] - gB[j]
        val C = fC[i] - gC[j]
        
        totalArea += integrateAbsQuadratic(A, B, C, currentX, nextX)
        
        // Сдвигаем указатели, если достигли границы соответствующего кусочка.
        if (abs(fBoundaries[i+1] - nextX) < eps) i++
        if (abs(gBoundaries[j+1] - nextX) < eps) j++
        currentX = nextX
    }
    
    writer.write(String.format("%.10f", totalArea))
    writer.newLine()
    writer.flush()
    reader.close()
    writer.close()
}

// Функция вычисления интеграла от |A*x^2+B*x+C| на промежутке [L, R]
fun integrateAbsQuadratic(A: Double, B: Double, C: Double, L: Double, R: Double): Double {
    val eps = 1e-12
    if (R - L < eps) return 0.0
    // Если полином практически постоянен: A и B малы.
    if (abs(A) < eps && abs(B) < eps) {
        return abs(C) * (R - L)
    }
    // Определим антидериватив F(x) = A/3*x^3 + B/2*x^2 + C*x.
    fun F(x: Double): Double = A * x * x * x / 3.0 + B * x * x / 2.0 + C * x
    // p(x) = A*x^2+B*x+C.
    fun p(x: Double): Double = A * x * x + B * x + C

    // Массив для точек разбиения. В худшем случае добавятся две корневые точки плюс L и R.
    val pts = DoubleArray(4)
    var cnt = 0
    pts[cnt++] = L
    if (abs(A) < eps) {
        // Линейный случай: p(x) = B*x+C, при B != 0 (иначе обработан выше)
        if (abs(B) >= eps) {
            val root = -C / B
            if (root > L + eps && root < R - eps) {
                pts[cnt++] = root
            }
        }
    } else {
        // Квадратичный случай
        val D = B * B - 4.0 * A * C
        if (D >= 0.0) {
            val sqrtD = sqrt(D)
            val r1 = (-B - sqrtD) / (2.0 * A)
            val r2 = (-B + sqrtD) / (2.0 * A)
            if (r1 > L + eps && r1 < R - eps) pts[cnt++] = r1
            if (r2 > L + eps && r2 < R - eps) pts[cnt++] = r2
        }
    }
    pts[cnt++] = R
    // Сортировка (количество точек не более 4)
    for (i in 0 until cnt) {
        for (j in i + 1 until cnt) {
            if (pts[i] > pts[j]) {
                val tmp = pts[i]
                pts[i] = pts[j]
                pts[j] = tmp
            }
        }
    }
    var area = 0.0
    // Интегрируем по каждому отрезку, где знак p(x) постоянен.
    for (i in 0 until cnt - 1) {
        val aInt = pts[i]
        val bInt = pts[i+1]
        if (bInt - aInt < eps) continue
        val mid = (aInt + bInt) / 2.0
        val sign = if (p(mid) >= 0) 1.0 else -1.0
        area += sign * (F(bInt) - F(aInt))
    }
    return abs(area)
}