题目链接:http://poj.org/problem?id=2785
Description
The SUM problem can be formulated as follows: given four lists A, B, C, D of integer values, compute how many quadruplet (a, b, c, d ) ∈ A x B x C x D are such that a + b + c + d = 0 . In the following, we assume that all lists have the same size n .
Input
The first line of the input file contains the size of the lists n (this value can be as large as 4000). We then have n lines containing four integer values (with absolute value as large as 228 ) that belong respectively to A, B, C and D .
Output
For each input file, your program has to write the number quadruplets whose sum is zero.
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
Hint
Sample Explanation: Indeed, the sum of the five following quadruplets is zero: (-45, -27, 42, 30), (26, 30, -10, -46), (-32, 22, 56, -46),(-32, 30, -75, 77), (-32, -54, 56, 30).
题目大意,给出n行数,没行数有4个数字,从四列数字中找出一组数字,让他们之和等于0,问有多少种组合;
思路:暴力肯定超时,因此我们可以先将后两项的所有组合处理出来,然后对于每前两项,二分查找有没有符合要求的数字,注意,可能有重复的出现,因此我i们要找他们的边界值,找出重复的个数;复杂度O(n^2logn)
ac:
#include<stdio.h>
#include<string.h>
#include<math.h>
//#include<map>
//#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
#define mod 1000000007
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// 水印
//std::ios::sync_with_stdio(false);
int n;
ll arr[4100][5];
ll sum2[16000100];
bool cmp(ll a,ll b)
{
return a<b;
}
int main()
{
std::ios::sync_with_stdio(false);
while(cin>>n)
{
ll ans=0;
clean(arr,0);
clean(sum2,0);
for(int i=1;i<=n;++i)
{
for(int j=1;j<=4;++j)
cin>>arr[i][j];
}
int k=1;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
sum2[k++]=arr[i][3]+arr[j][4];
}
sort(sum2+1,sum2+k,cmp);
// for(int i=0;i<=k;++i)
// cout<<sum2[i]<<endl;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
{
ll sum1=arr[i][1]+arr[j][2];
int l=0,r=k,mid;
while(r-l>1)
{
mid=(l+r)>>1;
if(sum1+sum2[mid]>0)
r=mid-1;
else if(sum1+sum2[mid]<0)
l=mid;
else//最后符合的向取最左边 (右向左逼近)
r=mid;
}
//cout<<r<<" "<<l<<" ";
int ansl=r;
l=0,r=k;
while(r-l>1)
{
mid=(l+r)>>1;
if(sum1+sum2[mid]>0)
r=mid;
else if(sum1+sum2[mid]<0)
l=mid+1;
else//最后符合的向取最右边 (左向右逼近)
l=mid;
}
//cout<<r<<" "<<l<<" ";
int ansr=l;
//cout<<i<<" "<<ansr<<" "<<ansl<<" ";
//结果可能是一个范围
if(ansr>ansl&&(sum1+sum2[ansr]==0&&sum1+sum2[ansl]==0))
ans=ans+ansr-ansl+1;
else if(ansr==ansl&&sum1+sum2[ansl]==0)
ans++;
}
}
cout<<ans<<endl;
}
}