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 2
28 ) 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
5Hint
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).
题目大意:给一个4*N 的数列,在每一列中找一个数,使这四个数加起来的和为0,问有多少种组合方法。之前一直不相信二分查找的力量,做了这道题过后算是彻底服了。举个例子,你要从一个元素有10的九次方个的数组中找出一个元素,for循环的话有十亿级别,而二分查找只用9log2(10),不到45。也就是说for循环要用十亿秒(多少年了)的问题二分法一分钟不到就可以做出来。由于数据量巨大(N<=4000),若用四重for循环的话是4的4000次方,铁定超时。可以先将前两列和后两列的总共有可能的和求出来,分别组成cnt1,cnt2数组,再对cnt1排序,再用每一个cnt2中的元素对cnt1进行二分查找,即(cnt1[mid]+cnt2[i]==0),找到后从Mid开始往两边搜,搜出此cnt2的方案总数。中间有许多细节需要处理好,尤其是二分边界的处理,这里就不赘述,请看代码。
#include <iostream> #include <stdio.h> #include <algorithm> using namespace std; int cnt1[16000002],cnt2[16000002]; int main() { int n,i,a[4002],b[4002],c[4002],d[4002],left,right,mid,ans=0,total,j,flag,k; scanf("%d",&n); for (i=0;i<=n-1;i++) { scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]); } total=0; for (i=0;i<=n-1;i++) { for (j=0;j<=n-1;j++) { cnt1[total]=a[i]+b[j]; cnt2[total]=c[i]+d[j]; total++; } } sort(cnt1,cnt1+n*n); for (i=0;i<=n*n-1;i++) { left=0; right=n*n-1; flag=0; while(right-left>=2) { mid=(left+right)/2; if (cnt2[i]+cnt1[mid]==0) { for(j=mid+1;cnt1[j]==cnt1[mid]&&j<=n*n-1;j++) { ans++; } for(k=mid-1;cnt1[k]==cnt1[mid]&&k>=0;k--) { ans++; } ans++; flag=1; break; } else if(cnt2[i]+cnt1[mid]>0) { right=mid; } else if (cnt2[i]+cnt1[mid]<0) { left=mid; } } if (cnt2[i]+cnt1[right]==0&&flag==0) { ans++; } if (cnt2[i]+cnt1[left]==0&&flag==0) { ans++; } } printf("%d",ans); return 0; }