Sum为0的值SUM问题可以表示如下:给定四个列表A,B,C,D的整数值,计算多少个四元组(a,b,c,d)∈A×B×C× D是这样的a + b + c + d = 0.
在下文中,我们假设所有列表具有相同的大小n。输入输入以一行上的单个正整数开始,表示后面的案例数,每个案例如下所述。该行后面是一个空行,两个连续输入之间也有一个空行。输入文件的第一行包含列表n的大小(此值可以大到4000)。然后,我们有n行包含四个整数值(绝对值大到2 28),它们分别属于A,B,C和D.输出对于每个测试用例,程序必须写入总和为零的四元组数。两个连续案例的输出将用空行分隔。
样品输入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
样品输出
5
样品说明:的确,以下五个四联体的总和为零:( - 45,-27,42,30),(26,30,-10,-46),( - 32,22,56,-46),( - 32, 30,-75,77),( - 32,-54,56,30)。
题解:
题目不难,思想也可以,希望下次遇到同类型的题目会做。
如果用四重循环会超时,所以中途相遇法二分成 a+b = -(c+d), 只用两重循环加上一个二分查找就可以解决问题。
关于lower_bound和upper_bound的用法:在从小到大的排序数组中,
lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
源代码:
#include <iostream>
#include <algorithm>
#define maxn 4005
using namespace std;
int t, n, a[maxn], b[maxn], c[maxn], d[maxn], sum[maxn*maxn];
int main() {
cin >> t;
while(t--) {
cin >> n;
for(int i = 0; i < n; ++i) scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);//C语言输入
int k = 0, ans = 0;
for(int i = 0; i < n; ++i)
for(int j = 0; j < n; ++j)
sum[k++] = a[i] + b[j];
sort(sum, sum + k);
for(int i = 0; i < n; ++i)
for(int j = 0; j < n; ++j)
ans+=upper_bound(sum,sum + k,-c[i]-d[j]) - lower_bound(sum, sum + k, -c[i]-d[j]);
cout << ans ;
if(t) cout << endl << endl;
}
return 0;
}