Farmer John Solves 3SUM
Explicación
Aunque el problema puede parecer intimidante al principio, ayuda pensar en cómo un rango más pequeño está conectado a otro.
Si es igual al número de tripletas no ordenadas que suman cero entre , ¿de qué estados depende esto?

Podemos elegir excluir un extremo o el otro, lo que nos da una imagen como esta (recordatorio de no contar dos veces la superposición).

Aunque esto contará todas las tripletas entre ellos, no estamos teniendo en cuenta ninguna tripleta que use ambos elementos en y , ya que esas no están incluidas en nuestra transición “tipo PIE”.Nuestra transición toma todas las tripletas de y
Para hacer esto, podemos precalcular el número de tripletas que empiezan en y terminan en en tiempo almacenando las ocurrencias del complemento de y en un arreglo.
Más formalmente, nuestra transición final es:
donde es igual al número de tripletas que suman cero y empiezan en y terminan en .
Implementación
Complejidad temporal:
Nótese que no podemos almacenar en su propio arreglo debido a las restricciones de memoria.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAX_VAL = 1e6;
int main() {
freopen("threesum.in", "r", stdin);
freopen("threesum.out", "w", stdout);
cin.tie(0)->sync_with_stdio(0);
int n, q;
cin >> n >> q;
vector<int> val(n);
for (int i = 0; i < n; i++) {
cin >> val[i];
val[i] += MAX_VAL;
}
// number of triplets such that i and k are fixed
vector<vector<ll>> ways(n, vector<ll>(n, 0));
vector<int> frq(2 * MAX_VAL);
for (int i = n - 2; i >= 0; i--) {
// be careful to only consider values in between i and j
frq[val[i + 1]]++;
for (int j = i + 2; j < n; j++) {
// separate val from shifted amt
int compliment = (MAX_VAL * 3) - (val[i] + val[j]);
if (compliment >= 0 && compliment < (2 * MAX_VAL)) {
ways[i][j] = frq[compliment];
}
frq[val[j]]++;
}
for (int j = i + 1; j < n; j++) { frq[val[j]]--; }
}
// essentially 2D prefix sum on ways
for (int i = n - 1; i >= 0; i--) {
for (int j = i + 1; j < n; j++) {
ways[i][j] += (ways[i + 1][j] + ways[i][j - 1] - ways[i + 1][j - 1]);
}
}
for (int _ = 0; _ < q; _++) {
int l, r;
cin >> l >> r;
cout << ways[l - 1][r - 1] << '\n';
}
}import java.io.*;
import java.util.*;
public class Threesum {
static final int MAX_VAL = 1000000;
public static void main(String[] args) throws IOException {
Kattio io = new Kattio("threesum");
int N = io.nextInt();
int Q = io.nextInt();
int[] a = new int[N];
for (int i = 0; i < N; i++) { a[i] = io.nextInt(); }
long[][] dp = new long[N + 1][N + 1];
int[] cnt = new int[2 * MAX_VAL + 1];
// Calculate the number of k such that a[i] + a[j] + a[k] = 0 given i
// and j
for (int i = 0; i < N - 1; i++) {
for (int j = 0; j < N; j++) { cnt[a[j] + MAX_VAL] = 0; }
for (int j = i + 1; j < N; j++) {
int k = -a[i] - a[j];
if (k >= -MAX_VALUE && k <= MAX_VALUE) {
dp[i + 1][j + 1] += cnt[k + MAX_VAL];
}
cnt[a[j] + MAX_VAL]++;
}
}
for (int i = N; i >= 1; i--) {
for (int j = i + 1; j <= N; j++) {
dp[i][j] += dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1];
}
}
for (int i = 0; i < Q; i++) {
int a1 = io.nextInt();
int b = io.nextInt();
io.println(dp[a1][b]);
}
io.close();
}
// CodeSnip{Kattio}
}