1. 程式人生 > >POJ 2785-4 二分

POJ 2785-4 二分

 

要求: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);
}