Values whose Sum is 0

The SUM problem can be formulated as follows: given four lists A, B, C, D of integer values, compute how many quadruplet (a, b, c, d ) ∈ A x B x C x D are such that a + b + c + d = 0 . In the following, we assume that all lists have the same size n .

Input
The first line of the input file contains the size of the lists n (this value can be as large as 4000). We then have n lines containing four integer values (with absolute value as large as 2 28 ) that belong respectively to A, B, C and D .

Output
For each input file, your program has to write the number quadruplets whose sum is zero.
Sample Input
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

Hint
Sample Explanation: Indeed, the sum of the five following quadruplets is zero: (-45, -27, 42, 30), (26, 30, -10, -46), (-32, 22, 56, -46),(-32, 30, -75, 77), (-32, -54, 56, 30).

思路
将A+B数组的和存入一个新数组sum1,C+D数组的和的相反数(这样sum2的值在sum1找到了的话即A+B+C+D的值为0)存入一个新数组sum2。将sum1数组排序以便二分,C+D数组在sum1数组中查找第一次出现的位置和最后一次出现的位置,相减加一即得满足该值的情况数,最后汇总即是结果。

代码:

#include<iostream>
using namespace std;
#include<map>
#include<stack>
#include<set>
#include<queue>
#include<cstring>
#include<sstream>
#include<cmath>
#include<limits.h>
#include<algorithm>
#include<cstdio>
#define ll long long
const int N=20000000;

int n;
int A[4010];
int B[4010];
int C[4010];
int D[4010];

int sum1[N];
int sum2[N];
int k=1;

//计算元素第一次出现的位置 
int getStart(int value){
	int low=1,high=k-1;
	while(low<=high){
		int mid=low+((high-low)>>1);
		if(sum1[mid]<value){
			low=mid+1;
		}else if(sum1[mid]>value){
			high=mid-1;
		}else{
			if(mid==1||(sum1[mid-1]!=value)){ //如果我们查找到了等于value的下标,判断它下标是否为1或者它前一个位置是否等于value 
				return mid;
			}else{
				high=mid-1;//没找到,舍弃这个等于value的下标,往前找。 
			}
		}
	}
	return -1;
}

//计算元素最后一次出现的位置 ,与getStart基本相同 
int getEnd(int value){
	int low=1,high=k-1;
	while(low<=high){
		int mid=low+((high-low)>>1);
		if(sum1[mid]<value){
			low=mid+1;
		}else if(sum1[mid]>value){
			high=mid-1;
		}else{
			if(mid==k-1||(sum1[mid+1]!=value)){  
				return mid;
			}else{
				low=mid+1;
			}
		}
	}
	return -1;
}

int main() {

	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		scanf("%d%d%d%d",&A[i],&B[i],&C[i],&D[i]);
	}
	//int k=1; 计算A+B数组的和 
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			sum1[k++]=A[i]+B[j];
		}
	}
	sort(sum1+1,sum1+k);   //对A+B数组和进行排序以便二分 
	int m=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			sum2[m++]=(C[i]+D[j])*(-1);//乘以-1的原因是待会在sum1上如果查找到相同的元素则表明四个数的结果为0 
		}
	}
	int sum=0;//记录情况总数 
	for(int i=1;i<m;i++){
		int start=getStart(sum2[i]);  //考虑到有相同的元素,所以这里记录该元素的第一次出现的位置 
		int end=getEnd(sum2[i]); //最后一次出现的位置 
		if(start==-1){  //对于元素不存在的丢弃 
			continue;
		}
		sum+=end-start+1;  
	}
	cout<<sum<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值