题意:
给定4个n元素集合,要求分别从中选取一个元素a,b,c,d使得a+b+c+d=0.问,有多少种说法?
题解:
根据紫书算法,我们计算出a+b的所有和,放入vector数组中,同时计算c+d的所有和,放入vector数组中,之后暴力枚举a+b的所有和,在c+d和数组中二分查找-(a+b),这里需要注意的是原始的二分查找只会找到一个数据,数组中可能会有多个-(a+b),我们需要判断。PE了好几次,uva了格式很严格!
代码:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long LL;
vector<LL> sumA,sumB;
int solve(int mid,LL ans)
{
//cout<<mid<<ans<<endl;
int count=0;
int i=mid+1;
int j=mid-1;
while(sumB[i]==ans)
{
count++;
i++;
}
while(sumB[j]==ans)
{
count++;
j--;
}
return count;
}
int main()
{
vector<LL> data[4];
int T;
cin>>T;
LL num,tmp;
while(T--)
{
cin>>num;
for(int i=0;i<num;i++)
{
for(int j=0;j<4;j++)
{
cin>>tmp;
data[j].push_back(tmp);
}
}
LL sum1,sum2;
for(int i=0;i<num;i++)
{
for(int j=0;j<num;j++)
{
sum1 = data[0][i]+data[1][j];
sum2 = data[2][i]+data[3][j];
sumA.push_back(sum1);
sumB.push_back(sum2);
}
}
LL sizA = sumA.size();
LL sizB = sumB.size();
int ans=0;
sort(sumB.begin(),sumB.end());
for(int i=0;i<sizA;i++)
{
LL se = -sumA[i];
int right=sizB-1;
int left =0;
while(right>=left)
{
int mid = (right+left)>>1;
if(sumB[mid]>se){
right=mid-1;
}
else if(sumB[mid]<se)
{
left=mid+1;
}
else if(sumB[mid]==se){
//cout<<sumB[mid]<<se<<endl;
ans++;
int o=solve(mid,se);
ans+=o;
break;
}
}
}
cout<<ans<<endl;
if(T!=0) cout<<endl;
sumA.clear();
sumB.clear();
for(int j=0;j<4;j++)
{
data[j].clear();
}
}
return 0;
}