Titulo
ZJM tiene cuatro series A, B, C, D, cada serie tiene n números. ZJM toma un número de cada secuencia y quiere saber cuántos esquemas hacen que la suma de los cuatro números sea cero.
Cuando hay varios números idénticos en una secuencia, trátelos como números diferentes.
Entrada
La primera fila: n (que representa el número de números en la secuencia) (1≤n≤4000).
En las siguientes n filas, la fila i-ésima tiene cuatro números, que representan el número i-ésimo en la secuencia A, B, C, D (el número no excede la potencia 28 de 2).
Salida
Se emite el número de combinaciones diferentes.
Entrada de muestra
6
-45 22 42 -16
-41 -27 56 30
-36 53 -37 77
-36 30 -75 -46
26 -38 -10 62
-32 -54 -6 45
Salida de muestra
5
Ideas
Si los números en ABCD se enumeran directamente, la complejidad es O (n ^ 4) y la complejidad es demasiado alta. La idea es calcular A + B + C + D = 0.
Para reducir los puntos de enumeración y reducir la complejidad, puede enumerar A y B, y luego enumerar C y D, la complejidad es O (n ^ 2). La idea de hacer esto es calcular A + B = - (C + D).
Primero enumere A y B, calcule la suma de A + B y almacénelo en la matriz e [], y conviértalo en una matriz ordenada. Luego enumere C y D, y calcule cuántas veces aparece lo opuesto de C + D en e []. Al calcular cuántas veces ocurre lo contrario, se usa la dicotomía.
Al realizar la dicotomía, los límites izquierdo y derecho l y r toman respectivamente los límites izquierdo y derecho de la matriz e [], cuando l <r, loop, tome el valor en la posición de mid = (l + r) / 2, si es el valor que está buscando, verifique Si sus valores izquierdo y derecho son también el valor que está buscando, hasta que encuentre todos los puntos que cumplan con sus requisitos y devuelva el número de puntos encontrados; si es menor que el valor que desea, l se actualiza a mediados + 1; si es mayor que el valor que desea, r se actualiza a mediados de 1.
Código
#include <cstdio>
#include <algorithm>
using namespace std;
int a[4005],b[4005],c[4005],d[4005],e[4000*4000+5];
int n;
int find(int x){
int l=0,r=n*n,leftx=0,rightx=0;
while(l<=r){
int mid=(l+r)/2;
if(e[mid]==x){
while((mid+rightx)<n*n&&e[mid+rightx]==x){
rightx++;
}
while((mid-leftx)>=0&&e[mid-leftx]==x){
leftx++;
}
return leftx+rightx-1;
}
else if(e[mid]<x)
l=mid+1;
else if(e[mid]>x)
r=mid-1;
}
return 0;
}
int main() {
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
}
int k=0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
e[k]=a[i]+b[j];
k++;
}
}
int sum=0;
sort(e,e+n*n);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
sum+=find(-(c[i]+d[j]));
}
}
printf("%d",sum);
return 0;
}