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 折半搜索

POJ 2785 4 Values whose Sum is 0(折半搜索)

poj2785 4 Values whose Sum is 0

POJ - 2785 - 4 Values whose Sum is 0 - 二分折半查找

POJ 2785 4 Values whose Sum is 0(暴力枚举的优化策略)