题目:
ZJM 有四个数列 A,B,C,D,每个数列都有 n 个数字。ZJM 从每个数列中各取出一个数,他想知道有多少种方案使得 4 个数的和为 0。
当一个数列中有多个相同的数字的时候,把它们当做不同的数对待。
请你帮帮他吧!
输入:
第一行:n(代表数列中数字的个数) (1≤n≤4000)
接下来的 n 行中,第 i 行有四个数字,分别表示数列 A,B,C,D 中的第 i 个数字(数字不超过 2 的 28 次方)
输出:
输出不同组合的个数。
样例输入:
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
样例输出:
5
样例解释: (-45, -27, 42, 30), (26, 30, -10, -46), (-32, 22, 56, -46),(-32, 30, -75, 77), (-32, -54, 56, 30).
如果用暴力的方法,直接遍历计算A+B+C+D==0,复杂度高达O(N^4),数据范围为1~4000,肯定会超时。本题可以采用二分的方法,计算A+B=-(C+D),降低复杂度。
先计算A+B和C+D,得到数组ab,cd,然后调用sort函数将这两个数组分别排序。之后,循环在数组cd中,分别用二分搜索找到等于-ab[i]的元素的最大序号和最小序号。根据最大序号和最小序号对答案进行累加。
搜索等于ele的元素的最小的序号:
int searchMin(int *x,int ele,int num)//如果没找到与ele相等的元素则返回-1
{
int l=0,r=num,mid;
int ans=-1;
while(l<=r)
{
mid=(l+r)/2;
if(x[mid]==ele)
{
ans=mid;
r=mid-1;
}
else if(x[mid]>ele)
{
r=mid-1;
}
else if(x[mid]<ele)
{
l=mid+1;
}
}
return ans;
}
搜索等于ele的最大的元素的序号:
int searchMax(int *x,int ele,int num)//如果没找到与ele相等的元素则返回-1
{
int l=0,r=num,mid;
int ans=-1;
while(l<=r)
{
mid=(l+r)/2;
if(x[mid]==ele)
{
ans=mid;
l=mid+1;
}
else if(x[mid]>ele)
{
r=mid-1;
}
else if(x[mid]<ele)
{
l=mid+1;
}
}
return ans;
}
关键部分:
int first,last;
int ans=0;
for(int i=0;i<n*n;i++)
{
first=searchMin(cd,-1*ab[i],n*n-1);//数组cd中等于-ab[i]的元素的最小序号
last=searchMax(cd,-1*ab[i],n*n-1);//数组cd中等于-ab[i]的元素的最大序号
if(first==-1&&last==-1)//说明没有找到等于-ab[i]的元素
{
continue;
}
else if( (first==-1&&last!=-1) || (first!=-1&&last==-1) )//等于-ab[i]的元素只有一个
{
ans=ans+1;
}
else
{
ans=ans+last-first+1; //有多个元素
}
}
以下是完整代码:
#include<iostream>
#include<algorithm>
using namespace std;
int a[5000],b[5000],c[5000],d[5000];
int ab[30000000],cd[30000000];
int n;
int searchMin(int *x,int ele,int num)
{
int l=0,r=num,mid;
int ans=-1;
while(l<=r)
{
mid=(l+r)/2;
if(x[mid]==ele)
{
ans=mid;
r=mid-1;
}
else if(x[mid]>ele)
{
r=mid-1;
}
else if(x[mid]<ele)
{
l=mid+1;
}
}
return ans;
}
int searchMax(int *x,int ele,int num)
{
int l=0,r=num,mid;
int ans=-1;
while(l<=r)
{
mid=(l+r)/2;
if(x[mid]==ele)
{
ans=mid;
l=mid+1;
}
else if(x[mid]>ele)
{
r=mid-1;
}
else if(x[mid]<ele)
{
l=mid+1;
}
}
return ans;
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i]>>b[i]>>c[i]>>d[i];
}
int cnt=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
ab[cnt++]=a[i]+b[j];
}
}
cnt=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
cd[cnt++]=c[i]+d[j];
}
}
sort(ab,ab+n*n);
sort(cd,cd+n*n);
int first,last;
int ans=0;
for(int i=0;i<n*n;i++)
{
first=searchMin(cd,-1*ab[i],n*n-1);
last=searchMax(cd,-1*ab[i],n*n-1);
if(first==-1&&last==-1)
{
continue;
}
else if( (first==-1&&last!=-1) || (first!=-1&&last==-1) )
{
ans=ans+1;
}
else
{
ans=ans+last-first+1;
}
}
cout<<ans;
}