POJ 2785-4 二分
阿新 • • 發佈:2018-12-04
要求:n行數,每行有四個數,ai,bi,ci,di,求有多少種組合方式,使a+b+c+d=0,這四個數可以不在一行。n<=4000,a,b,c,d<=2^28。
方法:折半列舉。
這題本來兩個二重迴圈和兩個map準備很快解決掉,但是直接TLE,後來發現二分查詢比map查詢快。
1.用二重迴圈分別記錄所有a+b和所有c+d的結果,然後將c+d的結果存起來並排序,掃a+b的值,二分搜尋儲存c+d的陣列,有幾個值是-a-b。
2.這其實是二分的策略,只是二分的答案是一個連續的子序列。
#include<stdio.h> #include<string.h> #include<algorithm> #include<map> using namespace std; map<long long,long long>map1; int num1; long long ab[16000001],cd[16000001]; int main() { int n,i,j,k,p,q,cnt=0,l,r,mid,num,temp; long long a[4001],b[4001],c[4001],d[4001]; scanf("%d",&n); for(i=0;i<n;i++) scanf("%lld%lld%lld%lld",&a[i],&b[i],&c[i],&d[i]); for(i=0;i<n;i++) { for(j=0;j<n;j++) { ab[cnt]=a[i]+b[j]; cd[cnt]=c[i]+d[j]; cnt++; } } sort(cd,cd+cnt); num=0; for(i=0;i<cnt;i++) { l=0,r=cnt-1,mid=(l+r)/2; while(cd[mid]!=(-ab[i])&&l<=r) { mid=(l+r)/2; if(cd[mid]>(-ab[i])) r=mid-1; else if(cd[mid]<(-ab[i])) l=mid+1; } if(cd[mid]!=(-ab[i])) continue; num++; temp=mid; while(temp-1>=0&&cd[--temp]==(-ab[i])) num++; temp=mid; while(temp+1<cnt&&cd[++temp]==(-ab[i])) num++; } printf("%d\n",num); }