poj2785(折半枚举)
Posted codeoosacm
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj2785(折半枚举)相关的知识,希望对你有一定的参考价值。
给定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 ", 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(折半枚举)的主要内容,如果未能解决你的问题,请参考以下文章
C - 4 Values whose Sum is 0 POJ - 2785 (折半枚举)(二分搜索)
POJ 2785 4 Values whose Sum is 0(折半搜索)
poj2785 4 Values whose Sum is 0