四个数列:判断使四个数列中取出的数和为0共有多少种方案。c++

四个数列

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

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

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

(解答:(-45, -27, 42, 30), (26, 30, -10, -46), (-32, 22, 56, -46),(-32, 30, -75, 77), (-32, -54, 56, 30)

思路:

  • 第一反应暴力,可以四重循环算出所有结果,等于0就++。但是这样复杂度就是n4,肯定会爆。
  • 所以尝试使用二分的思想,可以分别枚举A+B和C+D,对于每一个C+D的结果,寻找在A+B中是否有它的相反数。
  • 如果直接暴力在A+B中找的话,复杂度并没有降多少,所以可以先对A+B的答案进行排序,然后继续利用二分查找的想法,锁定相反数的位置(利用二分法查找第一个相反数的位置和最后一个相反数的位置,最后一个的位置-第一个的位置+1=该相反数出现的次数)
#include<algorithm>
#include<cmath> 
#include<vector>
#include<iostream>
using namespace std;
int a[1000001];
int b[1000001];
int c[1000001];
int d[1000001];
vector<int>ab;
int findbegin(int x)
{
	int l=0,r=ab.size()-1,ans=-1;
	while(l<=r)
	{
		int m=(l+r)/2;
		if(ab[m]==x)
		{
			ans=m;
			r=m-1;
		}
		else if(ab[m]>x)	r=m-1;
		else l=m+1;
	}
	return ans;
}
int findend(int x)
{
	int l=0,r=ab.size()-1,ans=-1;
	while(l<=r)
	{
		int m=(l+r)/2;
		if(ab[m]==x)
		{
			ans=m;
			l=m+1;
		}
		else if(ab[m]>x)	r=m-1;
		else l=m+1;
	}
	return ans;
}
int main()
{
	int n;
	cin>>n;
	int ans=0;
	for(int i=0;i<n;i++)
	{
		
		cin>>a[i]>>b[i]>>c[i]>>d[i];
	}
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			ab.push_back(a[i]+b[j]);
		}
	}
	sort(ab.begin(),ab.end());
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			int temp=(c[i]+d[j])*(-1);//枚举c+d,若互为相反数则确定是一组 
			int l=findbegin(temp);
			int r=findend(temp);
			if(l!=-1) ans+=(r-l+1);
		}
	}
	cout<<ans<<endl;
	return 0;
}
发布了29 篇原创文章 · 获赞 1 · 访问量 943

猜你喜欢

转载自blog.csdn.net/qq_44654498/article/details/104926493