四个数列-整数二分问题

题目

在这里插入图片描述

题目大意

本题给出4个数组A、B、C、D,均包含n个整数,要求从每个数组中取一个数,使得这四个数的和为0,求一共有多少种方案。

解题思路

本题需要借助二分的方法来实现,但是一开始很难发现二分入手方向。对于取四个数字使得和为零,可以转化为取两个互为相反数的数,即将A中每一个数与B中每一个数求和组成新数组PA,同理将C中每一个数与D中每一个数求和组成新数组PC,PA和PC的长度为2n。之后,遍历PC,用二分来得到-PC[i]在PA中的个数,最后的个数和即为方案总数。当使用二分找到-PC[i]对应的位置时,可以在该位置前后寻找相同的元素,便能得到个数。

具体代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<ctime> 
#include<iomanip>
#include<vector>
#include<queue>
#define ll long long
#define ld long double
using namespace std;

int a[4005],b[4005],c[4005],d[4005];
vector<int> pa,pc;
int p,q;

int Bfind(int begin, int end, int x)
{
	int ans = -1;
	int l = begin,r = end;
	while(l <= r)
	{
		int mid = (l + r) >> 1;
		if(pa[mid] == x)
		{
			ans = mid;
			l = mid + 1;
		}
		else if(pa[mid] > x)
		{
			r = mid - 1;
		}
		else
		{
			l = mid + 1;
		}
	}
	return ans;
}

int main()
{
    int n,ans = 0,cnt = 0;
    cin >> n;
    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++)
		{
			pa.push_back(a[i]+b[j]);
			pc.push_back(c[i]+d[j]);
		}
	}
	sort(pa.begin(),pa.end());
	for(int i = 0; i < pc.size(); i++)
	{
		int mid = Bfind(0,pa.size(),-pc[i]);
		if(mid == -1)
		{
			continue;
		}
		int left = mid;
		int right = mid;
		for(int j = mid - 1; ; j--)
		{
			if(pa[j] == pa[mid])
			{
				left--;
			}
			else
			{
				break;
			}
		}
		for(int j = mid + 1; ; j++)
		{
			if(pa[j] == pa[mid])
			{
				right++;
			}
			else
			{
				break;
			}
		}
		ans = ans + (right - left + 1);
//		cout << ans << " " << left << " " << right << endl;
	}
	cout << ans;
    return 0;
}
原创文章 46 获赞 1 访问量 1519

猜你喜欢

转载自blog.csdn.net/weixin_43676449/article/details/104825858
今日推荐