Handshake
Explicación
Es más fácil resolver este problema considerando primero una solución cuadrática. Para resolverlo en , podemos hallar todos los valores posibles de apretones de mano, ordenarlos y tomar los mayores.
Para optimizar esta solución, podemos usar búsqueda binaria. Hacemos búsqueda binaria sobre el valor tal que nuestros apretones de mano más grandes tienen valores y los restantes tienen valores .
Para esto, ordenamos en orden no creciente y construimos un arreglo de sumas de prefijos, . Luego, para cada valor de que comprobamos con búsqueda binaria, usamos dos punteros para calcular el y el totales. Para cada índice , hallamos el último índice tal que . Al decrementar en , nunca decrementamos , lo que permite un recorrido en .
Nuestra adición a se obtiene del hecho de que si es el último índice tal que , podemos emparejar a la persona del índice con las primeras personas.
Nuestra adición a se obtiene del hecho de que cada uno de los apretones de mano, , contribuye exactamente una vez para todo con . Esto da la fórmula , que es equivalente a . Podemos usar sumas de prefijos para hallar en , lo que da nuestra fórmula.
Para el óptimo, el resultado es . Esto es porque, para el resultado óptimo, los apretones de mano con valor exactamente se pueden tomar o no. Cuando hallamos el óptimo, incluirá todos los apretones de mano de valor . Para ajustar este sobreconteo, restamos , ya que no deberíamos tomar apretones de mano de valor exactamente .
Implementación
Complejidad temporal:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAXV = 200000;
int main() {
int n;
ll m;
cin >> n >> m;
vector<int> a(n);
vector<ll> pref(n + 1, 0);
for (int &x : a) { std::cin >> x; }
sort(a.rbegin(), a.rend());
for (int i = 0; i < n; i++) { pref[i + 1] = a[i] + pref[i]; }
int lo = 0, hi = MAXV;
ll res = 0;
while (lo <= hi) {
ll count = 0, benefit = 0;
int k = lo + (hi - lo) / 2;
int j = 0;
for (int i = n - 1; i >= 0; i--) {
while (j < n && a[i] + a[j] >= k) { j++; }
count += j;
benefit += 1LL * j * a[i] + pref[j];
}
if (count >= m) {
lo = k + 1;
res = benefit - (count - m) * k;
} else {
hi = k - 1;
}
}
cout << res << '\n';
return 0;
}import java.io.*;
import java.util.*;
public class Main {
private static int MAXV = 200000;
public static void main(String[] args) throws Exception {
Kattio io = new Kattio();
int n = io.nextInt();
long m = io.nextLong();
Integer[] a = new Integer[n];
for (int i = 0; i < n; i++) { a[i] = io.nextInt(); }
Arrays.sort(a, Collections.reverseOrder());
long[] pref = new long[n + 1];
for (int i = 0; i < n; i++) { pref[i + 1] = a[i] + pref[i]; }
int lo = 0, hi = MAXV;
long res = 0;
while (lo <= hi) {
long count = 0, benefit = 0;
int k = lo + (hi - lo) / 2;
int j = 0;
for (int i = n - 1; i >= 0; i--) {
while (j < n && a[i] + a[j] >= k) { j++; }
count += j;
benefit += (long)j * a[i] + pref[j];
}
if (count >= m) {
lo = k + 1;
res = benefit - (count - m) * k;
} else {
hi = k - 1;
}
}
io.println(res);
io.close();
}
// BeginCodeSnip{Kattio}
}