1. 程式人生 > >poj2785(折半枚舉)

poj2785(折半枚舉)

using 我們 pac long long nbsp i++ 代碼 upper bsp

給定A,B,C,D四個集合,每個集合有n個數,一個元組t={a,b,c,d},其中a,b,c,d分別屬於ABCD,且a+b+c+d=0

求這樣的元組有多少個

1<=n<=4000

|ai,bi,ci,di|<2^28

分析:

暴力枚舉n^4顯然行不通,n^3也不可

我們可以先n^2計算出a+b的所有值,然後對於每個c+d,尋找-(c+d)=a+b

至於查找過程,把{a+b}進行排序然後二分查找

代碼:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<string
> 5 #include<queue> 6 #include<vector> 7 #include<set> 8 #include<map> 9 #include<cmath> 10 #include<algorithm> 11 12 #define ll long long 13 #define mem(a,b) memset(a,b,sizeof(a)) 14 15 using namespace std; 16 const int maxn=4004; 17 int sum[maxn*maxn]; 18
int A[maxn],B[maxn],C[maxn],D[maxn]; 19 int cnt=0; 20 int main() 21 { 22 //freopen("in.in","r",stdin); 23 int n; 24 cin>>n; 25 for(int i=1;i<=n;i++) 26 { 27 scanf("%d%d%d%d",&A[i],&B[i],&C[i],&D[i]); 28 } 29 for(int i=1;i<=n;i++) 30 { 31
for(int j=1;j<=n;j++) 32 { 33 sum[cnt++]=A[i]+B[j]; 34 } 35 } 36 sort(sum,sum+cnt); 37 ll res=0; 38 for(int i=1;i<=n;i++) 39 { 40 for(int j=1;j<=n;j++) 41 { 42 int t=-(C[i]+D[j]); 43 int l=upper_bound(sum,sum+cnt,t)-lower_bound(sum,sum+cnt,t); 44 res+=l; 45 } 46 } 47 printf("%ld\n", res); 48 }

註意:對於每一個c+d,可能不止有一個a+b=-(c+d),要把所有滿足條件的a+b都舉出來,所以是

int l=upper_bound(sum,sum+cnt,t)-lower_bound(sum,sum+cnt,t);
res+=l;

學到了什麽:

  lower_bound是返回大於等於待查找元素的第一個值的位置

  upper_bound是返回大於待查找元素的第一個值的位置(之前一直以為二者是相對的,upper_bound返回的是小於等於待查找元素的第一個位置)

  

poj2785(折半枚舉)