# 1046. 4个值的和为0

#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn=4000;
int n;
int A[maxn],B[maxn],C[maxn],D[maxn];
int CD[maxn*maxn];

void solve() {
for(int i=0; i<n; ++i)
for(int j=0; j<n; ++j)
CD[i*n+j]=C[i]+D[j];
sort(CD,CD+n*n);

long long ans=0;
for(int i=0; i<n; ++i) {
for(int j=0; j<n; ++j) {
int cd=-A[i]-B[j];
ans += upper_bound(CD, CD+n*n, cd) - lower_bound(CD, CD+n*n, cd);
}
}
printf("%lld\n",ans);
}

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]);
}
solve();
return 0;
}


[em:14]

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define HASHSIZE 19999999//19999999是一个素数
#define N 4005
#define MAX (1<<29) //绝对值小于2^28则用一个大数MAX来保护下标
typedef long l;
typedef struct Hash {
l key, size;//关键字和出现的次数
struct Hash*next;
hash*hashing[HASHSIZE];//hash表
l a[N], b[N], c[N], d[N], n, ans;
hash*findhash(l n)
{
l a = n % HASHSIZE;
hash*p = hashing[a];
while (p)//查找链表。用平衡树更快，不过这个代码量。。。
if (p->key == n)
return p;
else
p = p->next;
return NULL;
}
hash*newhash(l n)//建立新节点
{
hash*node = (hash*)malloc(sizeof(hash));
node->key = n; node->size = 1;
node->next = NULL;
return node;
}
{
hash*p = findhash(n); int a = n % HASHSIZE;//采用直接取余法,优点:快
if (p)//假如出现过
p->size++;//次数加一
else
{//没出现过,创建新节点 插入链表头部
hash*pnode = hashing[a];
hashing[a] = newhash(n);
hashing[a]->next = pnode;
}
}
int main()
{
scanf("%ld", &n);
for (l i = 1; i <= n; i++)
scanf("%ld%ld%ld%ld", &a[i], &b[i], &c[i], &d[i]);
for (l i = 1; i <= n; i++)
for (l j = 1; j <= n; j++)
addhash(MAX + a[i] + b[j]);
for (l i = 1; i <= n; i++)
for (l j = 1; j <= n; j++)
{
hash*p = findhash(MAX - c[i] - d[j]);
if (p)//假如出现过
ans += p->size;//加上出现的次数
}
printf("%ld\n", ans);
}