Conteo de Pares en Secuencias con Discretización y Búsqueda Binaria

Descripción del Problema

Se te proporciona una secuencia de (n) enteros, donde el (i)-ésimo elemento es (a_i). Además, se dan dos enteros (x) y (y) (con (x \le y)).

Un par de enteros ((i, j)) se considera interesante si cumple las siguientes condiciones:

  • (1 \le i < j \le n);
  • Si se eliminan los elementos en las posiciones (i) y (j) de la secuencia, la suma de los elementos restantes está entre (x) y (y) inclusive.

Tu tarea es determinar el número de pares interesantes en la secuencia dada.

Entrada

La primera línea contiene un entero (t) ((1 \le t \le 10^4)) - el número de casos de prueba.

Cada caso de prueba consiste en dos líneas:

  • La primera línea contiene tres enteros (n, x, y) ((3 \le n \le 2 \cdot 10^5), (1 \le x \le y \le 2 \cdot 10^{14}));
  • La segunda línea contiene (n) enteros (a_1, a_2, \dots, a_n) ((1 \le a_i \le 10^9)).

Restricción adicional: la suma de todos los (n) en todos los casos de prueba no excede (2 \cdot 10^5).

Salida

Para cada caso de prueba, imprime un entero - el número de pares interesantes en la secuancia dada.

Ejemplo

Entrada


7
4 8 10
4 6 3 6
6 22 27
4 9 6 3 4 5
3 8 10
3 2 1
3 1 1
2 3 4
3 3 6
3 2 1
4 4 12
3 3 2 1
6 8 8
1 1 2 2 2 3
  

Salida


4
7
0
0
1
5
6
  

Enfoque para la Solución

Primero, derivamos la fórmula. Dado que la secuencia es un arreglo (A) y (S = \sum_{i=1}^n A[i]), la condición para un par ((i, j)) ser enteresante es:

(x \le S - A[i] - A[j] \le y)

Esto implica:

(S - y - A[i] \le A[j] \le S - x - A[i])

Podemos enuemrar (A[i]) para obtener el rango de (A[j]) y contar cuántos elementos caen en ese rango. Para manejar los grandes rangos, usamos discretización y búsqueda binaria.

Es importante notar que este método también cuenta pares donde (i = j) o (i > j), por lo que debemos ajustar el resultado final restando estos casos.

Código

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 2e5 + 5;

void solve() {
    ll n, x, y;
    cin >> n >> x >> y;

    ll S = 0;
    vector<ll> A(n), B(3 * n + 1);
    vector<ll> dct;
    dct.push_back(-1E18); // Sentinela para evitar desbordamiento

    for (int i = 0; i < n; i++) {
        cin >> A[i];
        S += A[i];
    }

    for (int i = 0; i < n; i++) {
        dct.push_back(A[i]);
        dct.push_back(S - x - A[i]);
        dct.push_back(S - y - A[i]);
    }

    sort(dct.begin(), dct.end());
    dct.erase(unique(dct.begin(), dct.end()), dct.end());

    auto find = [&](ll p) -> int {
        return lower_bound(dct.begin(), dct.end(), p) - dct.begin();
    };

    for (int i = 0; i < n; i++) {
        B[find(A[i])] += 1;
    }
    for (int i = 1; i < 3 * n + 1; i++) {
        B[i] += B[i - 1];
    }

    ll res = 0, ans = 0;
    for (int i = 0; i < n; i++) {
        res += B[find(S - x - A[i])] - B[find(S - y - A[i]) - 1];
        if (S - A[i] - A[i] >= x && S - A[i] - A[i] <= y) ans++;
    }

    cout << (res - ans) / 2 << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed << setprecision(2);

    int t;
    cin >> t;
    while (t--) {
        solve();
    }

    return 0;
}

Etiquetas: discretización Búsqueda Binaria C++ codeforces algoritmos

Publicado el 10-22 17:33