poj2785(折半枚舉)
阿新 • • 發佈:2019-01-13
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]; 18int 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 { 31for(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(折半枚舉)