题目描述
求和问题可以被看做是以下的公式,给定 A,B,C,D 四个列表,计算有多少四元组满足 (a, b, c, d) ∈ A × B × C × D 且 a + b + c + d = 0。我们推测所有的列表都有 n 个数字。
注:不同的四元组是指元素位置不一样的四元组
数据范围 n<=2e3
样例输入
输入的第一个数字指明有 T 组。每一组这样描述,第一行是列表大小 n, 然后有 n 行。每一行都有四个整型数字,分别属于 A,B,C,D 四列。
样例输出
对于每一个测试用例,统计有多少个四元组满足他们的和是 0 。每一组数据一行。
Sample Input
1
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
Sample Output
5
基本思路
本题求的是四元组求和为零,我们可以先从简单的二元组开始考虑,对于二元组求和为零的问题,我们可以遍历其中一个元组的每个元素,并且在另一个元组中查找是否存在这个元素的相反数,如果存在,那么就有一组符合条件,查找的过程我们就可以采用二分搜索。依此类推,对于三元组,我们可以先把其中两个元组的各个元素可能的和都求出来,放入一个新的元组中,然后转换为二元组求和为零的问题,那么四元组的话,先两两求和,然后转换为二元组问题
AC代码
#include<iostream>
#include<algorithm>
using namespace std;
int sum[400010];
int ans;
//二分查找
void binary_search(int x,int length)
{
int left = 1, right = length-1;
while (left <= right)
{
int mid = (left + right) / 2;
//如果查找到这个值的话,我们不能急着直接令ans++
//因为这个元组中不一定只有一个元素等于x
//我们应该判断mid前面与mid后面是否也等于x,因此还要向前与向后搜索
if (sum[mid] == x)
{
ans++;
int i=mid,j=mid;
//向前搜索
while (sum[i - 1] == x)
{
ans++;
i--;
}
//向后搜索
while (sum[j + 1] == x)
{
ans++;
j++;
}
return;
}
else if (sum[mid] > x) right = mid - 1;
else left = mid + 1;
}
return;
}
int main()
{
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
//存储四元组
int arr[2010][10];
int i, j;
for (i = 1; i <= n; i++)
{
for (j = 1; j <= 4; j++)
{
cin >> arr[i][j];
}
}
//计算前面两个元组中所有元素可能的和
int k=1;
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
sum[k] = arr[i][1] + arr[j][2];
k++;
}
}
//注意:进行二分搜索的前提是有序的
//因为我是从sum[1]开始存储的,所以是sort(sum+1,sum+k)
//如果从sum[0]开始存储的话,这里应该是sort(sum,sum+k-1)
sort(sum + 1, sum + k);
int length = k;
//计算后两个元组中所有元素可能的和
//这里可以一边计算,一边进行二分搜索
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
int sum = arr[i][3] + arr[j][4];
//注意,查找的是给定值的相反数,所以要加个-号
binary_search(-sum, length);
}
}
cout << ans << endl;
//注意ans要重置,因为定义的是全局变量
ans = 0;
}
return 0;
}
时间也挺长的,如果有更加优秀的方法,欢迎指出!