1. 程式人生 > >poj 2785(折半列舉+二分搜尋)

poj 2785(折半列舉+二分搜尋)

傳送門:Problem 2785

 

題意:

  給定 n 行數,每行都有 4 個數A,B,C,D。

  要從每列中各抽取出一個數,問使四個數的和為0的所有方案數。

  相同數字不同位置當作不同數字對待。

題解:

  如果採用暴力的話,從4個數列中選擇數組合,共有(N^4)種選擇,故時間複雜度為O(N^4),指定會超時。

  但,如果將它們分成 AB,CD兩組,每組只有 N^2 個組合,而 N 的資料範圍為 N < 4000,故採用此種方法不會超時。

AC程式碼:

 1 #include<iostream>
 2 #include<cstdio>
 3
#include<algorithm> 4 using namespace std; 5 #define ll long long 6 const int maxn=4000+50; 7 8 int n; 9 int a[maxn*maxn]; 10 int b[maxn*maxn]; 11 int num[maxn][5]; 12 13 ll Solve() 14 { 15 int index=1; 16 for(int i=1;i <= n;++i) 17 for(int j=1;j <= n;++j) 18 {
19 a[index]=num[i][1]+num[j][2];//儲存所有的A+B的值 20 b[index]=num[i][3]+num[j][4];//儲存所有的C+D的值 21 index++; 22 } 23 sort(a+1,a+index); 24 sort(b+1,b+index); 25 ll res=0; 26 /** 27 A+B+C+D=0 -> C+D=-(A+B) 28 而C+D的所有值已經預處理好,故可通過二分查詢存在於b[]中 -(A+B) 的個數即可
29 **/ 30 for(int i=1;i < index;++i) 31 { 32 int t=lower_bound(b+1,b+index,-a[i])-b; 33 int k=0; 34 while(t < index && b[t] == -a[i])//查詢 -(A+B) 的個數 35 k++,t++; 36 res += k; 37 } 38 return res; 39 } 40 41 int main() 42 { 43 while(~scanf("%d",&n)) 44 { 45 for(int i=1;i <= n;++i) 46 for(int j=1;j <= 4;++j) 47 scanf("%d",&num[i][j]); 48 printf("%lld\n",Solve()); 49 } 50 return 0; 51 }
View Code