c++实现——四个数列

题意

ZJM 有四个数列 A,B,C,D,每个数列都有 n 个数字。ZJM 从每个数列中各取出一个数,他想知道有多少种方案使得 4 个数的和为 0。
当一个数列中有多个相同的数字的时候,把它们当做不同的数对待。
请你帮帮他吧!

Input

第一行:n(代表数列中数字的个数) (1≤n≤4000)
接下来的 n 行中,第 i 行有四个数字,分别表示数列 A,B,C,D 中的第 i 个数字(数字不超过 2 的 28 次方)

Output

输出不同组合的个数。

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

样例解释: (-45, -27, 42, 30),
(26, 30, -10, -46), (-32, 22, 56, -46)
(-32,30, -75, 77), (-32, -54, 56, 30).

思路

如果用四重循环暴力查找,很明显n⁴复杂度,我们没办法接受。
我们将四组数据先分成两组,即将a+b的所有组合做为一组数据ab,c+d的所有组合为一种数据cd;
然后再查找ab+cd=0的组合。查找过程可以采用二分思想,具体看代码。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int a[4005];
int b[4005];
int c[4005];
int d[4005];
int ab[16000010]; //a+b  4000个a+4000个b 最多组合16000000个
int cd[16000010]; //c+d
int ans=0;
int main(int argc, char** argv)
{
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		scanf("%d %d %d %d",&a[i],&b[i],&c[i],&d[i]);
	}
	int len=0;
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			ab[len]=a[i]+b[j];
			cd[len]=c[i]+d[j];
			len++;
		}
	}    //二重循环 计算a+b c+d
	sort(ab,ab+len); //将ab排序  才能使用二分  降低查找复杂度到log	
	int l,r,mid;
	for(int i=0;i<len;i++)
	{//枚举cd[i]  查找复合条件的第一个ab[i]
		l=0,r=len-1;  
		while(l<r)
		{//二分过程
			mid=(l+r)>>1;
			if(cd[i]+ab[mid]<0)
			{
				l=mid+1;
			}
			else
			{
				r=mid;
			}	
		}
		//cout<<ab[l]<<endl;	
		while(l!=len&&cd[i]+ab[l]==0)
		{//如果符合条件的不只之一 因为ab排过序 向后查找即可
			ans++;
			l++;
		}
	} 
	cout<<ans; 
	return 0;

}

总结

先分组相当于优化一下数据,然后用二分方法查找,降低复杂度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值