纯暴力是n^4果断超时。本题得解法可以采用二分搜索。时间复杂度n^2(logn)的样子,空间复杂度n^2。虽然还是非常巨大,但是本题可以险过,时间大概5s。
采用两个数组a[],b[]分别记录前两列所有可能的和与后两列所有可能的和,N^2级。然后对两个数组排序,便于统计每个值出现的次数,每个数组变为了两个数组,一个保存所有可能的值,只保存一个,仍为a[],另设一个数组c[],c[i]==(a[i]的个数)。b,d类似。然后对a中每一个数a[i]在b内二分搜索a[i]*(-1),如果存在b[j] == a[i]*(-1),返回d[j],没有就返回0。如果返回值不为0则总数加上d[j]*c[i]。
#include <iostream>
#include <algorithm>
#include <string.h>
#include <cstring>
#include <cmath>
#include <cstdio>
using namespace std;
/*
* 预处理+二分搜索
*/
const int N = 16000005;
int a[N], b[N], c[N], d[N];
int p[4005][4];
//二分搜索一个值在b数组中的个数
int search(int n, int x){
//
int l = 0, r = n - 1, mid;
while (l <= r){
mid = (l + r) / 2;
if (b[mid] == x)
return d[mid];
else if (b[mid] < x)l = mid + 1;
else r = mid - 1;
}
return 0;
}
int main(){
int n, k;
while (scanf("%d", &n) != EOF){
for (int i = 0; i < n; i++)
for (int j = 0; j < 4; j++)
scanf("%d", &p[i][j]);
//a保存前两列可能的和,b保存后两列可能的和
k = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
a[k++] = p[i][0] + p[j][1];
k = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
b[k++] = p[i][2] + p[j][3];
sort(a, a + k);//排序
sort(b, b + k);//【排序
int t = 0, h = 0;
c[0] = d[0] = 1;
//对数组a预处理,如果存在重复则记录这个值重复的次数
//而且重复的值只保留一个
for (int i = 1; i < k; i++){
if (a[i] == a[t])
c[t]++;
else {
t++;
a[t] = a[i];
c[t] = 1;
}
}
//b类似
for (int i = 1; i < k; i++){
if (b[i] == b[h])
d[h]++;
else {
h++;
b[h] = b[i];
d[h] = 1;
}
}
__int64 sum = 0;
for (int i = 0; i <= t; i++){
sum += search(h + 1, a[i] * (-1)) * c[i];
}
printf("%I64d\n", sum);
}
return 0;
}