【程序设计思维与实践 Week4 作业B】四个数列

题目描述:

ZJM 有四个数列 A,B,C,D,每个数列都有 n 个数字。ZJM 从每个数列中各取出一个数,他想知道有多少种方案使得 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

思路:

若对数据和一一枚举,则会到达n4的复杂度,明显会超时,因此我们采用首先使用前两个数组进行枚举,记录他们的和,然后再枚举后两个数组的和,同时看前两个数组中他们的相反数有多少个,并计入答案。这样复杂度可降到n2。在计算相反数有多少个时,曾采用map的记法,但仍然超时了,因此我们选择对前两个数组的和数组排序,然后进行二分,找出要找的数的第一个和最后一个位置,从而求出目标数据(后两个数组和的相反数)的个数。

代码:

#include <iostream>
#include<map>
#include<vector>
#include<algorithm>
#include<string.h>
using namespace std;
const int size=4000+10;
int d[4][size];
int sum[size*size];
int begin(int x,int left,int right)
{
	int ans=-1;
	while(left<=right)
	{
		int mid=(left+right)>>1;
		if(sum[mid]==x)
		{
			ans=mid;
			right=mid-1;
		}
		else if(sum[mid]<x)
			left=mid+1;
		else
			right=mid-1;
	}
	return ans;
}
int end(int x,int left,int right)
{
	int ans=-1;
	while(left<=right)
	{
		int mid=(left+right)>>1;
		if(sum[mid]==x)
		{
			ans=mid;
			left=mid+1;
		}
		else if(sum[mid]<x)
			left=mid+1;
		else
			right=mid-1;
	}
	return ans;
}
int main(int argc, char** argv) {
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		scanf("%d%d%d%d",&d[0][i],&d[1][i],&d[2][i],&d[3][i]);
	}
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			sum[i*n+j]=d[0][i]+d[1][j];
		}
	}
	sort(sum,sum+n*n);
	int count=0;
	int l,r;
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			int temp=d[2][i]+d[3][j];
			temp=0-temp;
			l=begin(temp,0,n*n-1);
			if(l==-1)
				continue;
			r=end(temp,0,n*n-1);
			count+=(r-l+1);
		}
	}
	cout<<count<<endl;
	return 0;
}
发布了25 篇原创文章 · 获赞 8 · 访问量 532

猜你喜欢

转载自blog.csdn.net/weixin_44034698/article/details/104874715