题目
题目大意
本题给出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;
}