四个数列和为零

问题描述

ZJM 有四个数列 A,B,C,D,每个数列都有 n 个数字。ZJM 从每个数列中各取出一个数,他想知道有多少种方案使得 4 个数的和为 0。当一个数列中有多个相同的数字的时候,把它们当做不同的数对待。
【输入】
第一行:n(代表数列中数字的个数) (1≤n≤4000)
接下来的 n 行中,第 i 行有四个数字,分别表示数列 A,B,C,D 中的第 i 个数字(数字不超过 2 的 28 次方)
【输出】
输出不同组合的个数。
【样例输入】
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

问题分析

1、A+B+C+D=0,可以转换为讨论A+B=-(C+D)
2、将AB数组依次加和形成数组a,CD数组依次加和形成数组b
3、排序a数组后,枚举b找它在a中的相反数的位置,计算得到相反数第一次和最后一次出现的位置
4、计算一个数在第一次和最后一次出现的位置时,用到二分思想

代码分析

mid=(l+r)>>1与mid=(l+r)/2的结果一样,但前者速度更快

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

int a[16000010],b[16000010];
int A[5000],B[5000],C[5000],D[5000];

int findl(int x,int n)//找到x的第一个位置 
{
	int l=0,r=n-1,ans=-1;
	while(l<=r)
	{
		int mid=(l+r)>>1;//速度快
		if(a[mid]==x)
		{
			ans=mid;
			r=mid-1;
		}
		else if(a[mid]>x) r=mid-1;  
		else l=mid+1; 
	} 
	return ans;
}

int findr(int x,int n)//找到x的最后一个位置,不存在返回-1 
{
	int l=0,r=n-1,ans=-1;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(a[mid]==x)
		{
			ans=mid;
			l=mid+1;
		}
		else if(a[mid]>x) r=mid-1;
		else l=mid+1; 
	}
	return ans;
}

int main()
{
	
 	int n;
 	cin>>n;
 	for(int i=0;i<n;i++)
 	{
 		cin>>A[i]>>B[i]>>C[i]>>D[i];
	}
	int k=0,sum=0;
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			a[k]=A[i]+B[j];
			b[k]=C[i]+D[j];
			k++; 
		}
	}
    sort(a,a+k);
    for(int i=0;i<k;i++)
	{
		int min=findl(-b[i],k);
		int max=findr(-b[i],k);
		if(max>=min&&max!=-1&&min!=-1)
		{
			sum+=max-min+1;
		} 
	} 
	cout<<sum<<endl;
}                             
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值