四个数列
题目描述
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
解题思路
1.我们可以两个for循环计算出a,b两个数组的所有和,然后再两个for循环找出c,d两个数组的和,然后找a+b的相反数再c+d中出现的次数
2.显然以上方法很复杂过不去,那么们就要进行一个二分查找的优化,我们将a+b的和存在数组中,然后对这个数组进行从小到大的排序,这样,我们再查找c+d的相反数再上面数组中左边出现的第一个位置和右边出现的最后一个位置ans+=右-左+1,okk
#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
const int maxn=4010;
int a[maxn],b[maxn],c[maxn],d[maxn];
int n;
int mp[maxn*maxn];
int findl(int x,int a[])
{
int l=0, r=n*n-1, ans=-1;
while(l<=r){
int mid=(l+r)/2;
if(a[mid]>=x){
ans=mid;
r=mid-1;
}
else l=mid+1;
}
return ans;
}
int findr(int x,int a[])
{
int l=0, r=n*n-1, ans=-1;
while(l<=r){
int mid=(l+r)/2;
if(a[mid]==x){
ans=mid;
l=mid+1;
}
else if(a[mid]>x) r=mid-1;
else l=mid+1;
}
return ans;
}
int main()
{
int answer=0;
cin>>n;
for(int i=0;i<n;i++)
// cin>>a[i]>>b[i]>>c[i]>>d[i];
scanf("%d %d %d %d",&a[i],&b[i],&c[i],&d[i]);
int mm=n*n;
int ij=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
mp[ij]=a[i]+b[j];
ij++;
}
}
sort(mp,mp+mm);
int temp;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
temp=c[i]+d[j];
int ll=findl(-temp,mp);
if(ll!=-1)
{
int rr=findr(-temp,mp);
if(rr!=-1) answer+=rr-ll+1;
}
}
}
cout<<answer;
return 0;
}