题目链接
题解:
要找四个数的和为零,最简单的方法暴力,四层for循环,但是肯定会超时,所以可以用二分,把a+b+c+d=0,转化为a+b=-(c+d),转化成两个数列,从一个数列中取出数X,去另一个数列中二分查找﹣X。
代码:
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int MAX_N=4e3+5;
const int MAX_M=16e6+5;
int a[MAX_N],b[MAX_N],c[MAX_N],d[MAX_N];
int n,s1[MAX_M],s2[MAX_M],k;
int bs(int s)
{
int l=0,r=k;
while(l<r){
int mid=l+(r-l)/2;
if(s<=s2[mid]) //遇到相同的会一直减少到第一次出现s的地方
r=mid;
else
l=mid+1;
}
int sum=0;
while(s2[l]==s&&l<k){ //统计重复的个数
sum++;
l++;
}
return sum;
}
int main()
{
while(scanf("%d",&n)!=EOF){
for(int i=0;i<n;i++)
scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
k=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
s1[k]=a[i]+b[j];
s2[k]=c[i]+d[j];
k++;
}
sort(s1,s1+k);
sort(s2,s2+k);
int num=0;
for(int i=0;i<k;i++)
num+=bs(-s1[i]);
printf("%d\n",num);
}
return 0;
}
方法二:
还可以用lower_bound代替上边自己手写的二分。
不懂lower_bound的点这里
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int MAX_N=4e3+5;
const int MAX_M=16e6+5;
int a[MAX_N],b[MAX_N],c[MAX_N],d[MAX_N];
int n,s1[MAX_M],s2[MAX_M],k;
int bs(int s)
{
int l=0,r=k;
/*while(l<r){
int mid=l+(r-l)/2;
if(s<=s2[mid])
r=mid;
else
l=mid+1;
}*/
int sum=0;
l=lower_bound(s2,s2+k,s)-s2;
while(s2[l]==s&&l<k){
sum++;
l++;
}
return sum;
}
int main()
{
while(scanf("%d",&n)!=EOF){
for(int i=0;i<n;i++)
scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
k=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
s1[k]=a[i]+b[j];
s2[k]=c[i]+d[j];
k++;
}
sort(s1,s1+k);
sort(s2,s2+k);
int num=0;
for(int i=0;i<k;i++)
num+=bs(-s1[i]);
printf("%d\n",num);
}
return 0;
}