题意:
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
样例解释:
(-45, -27, 42, 30), (26, 30, -10, -46), (-32, 22, 56, -46),(-32, 30, -75, 77), (-32, -54, 56, 30).
思路:
如果直接通过四个循环嵌套的话则时间复杂度过大,因此采用其他的方法。通过两个循环嵌套,得出两个数列的相加情况,并将其存储在一个容器中,并对此容器中的数进行排序。通过两个循环嵌套得出另外两个数列的相加值,并通过两个函数找出第一个和最后一个和前两个数列和相反的数的位置,得出最终结果。在两个查找函数中,应用二分查找进行查找位置,从0到容器中容量进行查找找出容器中的要求的值。
代码:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> temp;
int find1(int am)
{
am=-am;
int l=0;
int r=temp.size();
int count=-1;
while(l<=r)
{
int mid=(l+r)/2;
if(temp[mid]==am)
{
count=mid;
r=mid-1;
}
else if(temp[mid]>am)
{
r=mid-1;
}
else
{
l=mid+1;
}
}
return count;
}
int find2(int am)
{
am=-am;
int l=0;
int r=temp.size();
int count=-1;
while(l<=r)
{
int mid=(l+r)/2;
if(temp[mid]==am)
{
count=mid;
l=mid+1;
}
else if(temp[mid]>am)
{
r=mid-1;
}
else
{
l=mid+1;
}
}
return count;
}
int main()
{
int n;
cin>>n;
int count=0;
//int a1,a2;
int a[n],b[n],c[n],d[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++)
{
temp.push_back(a[i]+b[j]);
//a1=a[i]+b[j];
}
}
sort(temp.begin(),temp.end());
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
int am=c[i]+d[j];
int num1=find1(am);
int num2=find2(am);
if(num1!=-1&&num2!=-1)
count=count+num2-num1+1;
}
}
cout<<count;
return 0;
}