POJ 2785 折半枚举

#include <cstdio>
#include <iostream>
#include <algorithm>
#define LL long long
using namespace std;
int a[4][4005];
int b[2][4005*4005];

int main(){
    int n;
    while(cin >> n){
        for(int i = 0;i < n;i++){
            for(int j = 0;j < 4;j++){
                scanf("%d",&a[j][i]);
            }
        }
        int cnt1 = 0;
        int cnt2 = 0;
        for(int i = 0;i < n;i++){
            for(int j = 0;j < n;j++){
                b[0][cnt1++] = a[0][i] + a[1][j];
            }
        }
        for(int i = 0;i < n;i++){
            for(int j = 0;j < n;j++){
                b[1][cnt2++] = a[2][i] + a[3][j];
            }
        }
        sort(b[1],b[1]+cnt2);
        LL ans = 0;
        for(int i = 0;i < cnt1;i++){
            ans += upper_bound(b[1],b[1]+cnt2,0-b[0][i]) - lower_bound(b[1],b[1]+cnt2,0-b[0][i]);
        }
        cout << ans << endl;
    }
    return 0;
}

折半枚举就是讲原先整体的枚举分成部分枚举,然后再两个部分中利用符合条件的枚举的性质进行优化的

本来想了个用母函数做的,但是做完之后发现超时了;

这样想法本身并没有错误但是这里面会有一个母函数本质的问题,母函数的本质是将所有的序列都生成这时候其实就是相当于穷举了,但是这里面只考虑了0的系数所以这时候母函数就会生成太多的累赘的序列了,所以采用母函数是会超时的。下面是用母函数做的

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <stack>
#include <set>
#include <map>
#include <vector>

using namespace std;
#define INF 0x2fffffff
#define LL long long
#define MAX(a,b) ((a)>(b))?(a):(b)
#define MIN(a,b) ((a)<(b))?(a):(b)
int a[4][4005];
int main(){
    int t;
    int n;

    while(scanf("%d",&n)!=EOF){
        for(int i = 0;i < n;i++){
            for(int j = 0;j < 4;j++){
                scanf("%d",&a[j][i]);
            }
        }
        map<int,int> ma;
        queue<pair<int,int> > que;
        for(int i = 0;i < n;i++){
            que.push(make_pair(a[0][i],1));
        }
        for(int i = 1;i < 4;i++){
            for(int j = 0;j < n;j++){
                int si = que.size();
                for(int k = 0;k < si;k++){
                    pair<int,int> c = que.front();
                    que.pop();
                    que.push(c);
                    c.first = a[i][j] + c.first;

                    if(ma.find(c.first) == ma.end()){
                        ma[c.first] = 0;
                    }
                    ma[c.first] += c.second;
                }
            }
            while(!que.empty()) que.pop();
            for(map<int,int>::iterator ite = ma.begin();ite != ma.end();ite++){
                que.push(make_pair(ite->first,ite->second));
            }
            if(i != 3)
                ma.clear();
        }
        if(ma.find(0) != ma.end())
            printf("%d\n",ma[0]);
        else
            printf("%d\n",0);
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-02 17:12:51

POJ 2785 折半枚举的相关文章

poj 2549 折半枚举+二分

三重循环肯定TLE,所以采用“折半枚举”的方法+二分查找来提高速度,不同的是需要保存两个下标用来判定是否有重复元素. 1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 using namespace std; 6 7 const int N = 1000; 8 int a[N]; 9 int n, cnt; 10 11 struct

POJ 2785 折半搜索

https://vjudge.net/problem/POJ-2785 #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<set> #include<algorithm> #include<map> #define maxn 4005 typedef long long l

poj 2785 4 Values whose Sum is 0 折半枚举

题目链接:http://poj.org/problem?id=2785 枚举的一般思路就是先把所有的状态枚举出来 最后一次性判断该状态合法不合法 而折半枚举的思想是 先枚举一半的状态 把他们的状态存起来 排序 然后再枚举剩下一般 用目标反推前一半的期望状态 接下来在前一半的结果数组中查找是否有相应结果 之所以能优化是因为结果数组有序 就可以用二分搜索 复杂度从O(n^2 * n^2) 降到 O(n^2 * log(n^2))即(O(n^2 * log n)) 二分搜索的一个技巧 在有序数组中用二

poj 2785 4 Values whose Sum is 0(sort+二分)

题意: 给你ABCD四个集合,集合中数的个数都为N(N<=4000),如果分别在ABCD四个集合中取一个数,a b c d ,求有多少种可能使得a+b+c+d=0. 当然你可以尝试枚举所有的组合,绝对可以计算出结果,大概有N^4种吧,如果你有足够的时间还是可以算出来的,哈哈. 当然我不是用上面一种方法计算的,那样算肯定超时. 我的做法是求出所有a+b 到ab数组中, 和所有 c+d到cd数组中,然后排序,枚举每个ab,用二分在cd中查找有没有可能组成0.  有个问题就是二分只能返回一个结果,所以

【刷题记录】 &amp;&amp; 【算法杂谈】折半枚举与upper_bound 和 lower_bound

[什么是upper_bound 和 lower_bound] 简单来说lower_bound就是你给他一个非递减数列[first,last)和x,它给你返回非递减序列[first, last)中的第一个大于等于值x的位置. 而upper_bound就是你给他一个非递减数列[first,last)和x,它给你返回非递减序列[first, last)中的第一个大于值x的位置. STL中实现这两种函数的算法就是二分...... [upper_bound 和 lower_bound代码] //STl中的

POJ 2785(4 Values whose Sum is 0)

[题意描述] 对于给定的四个序列,从每个序列中选出一个数,并让四个数相加,输出所有相加和为0的情况数目. [解题思路] 我们可以考虑前两列的数字相加之和一定与后两列相加和互为相反数,那么我们可以枚举出前两列数字之和,并且,枚举出后两列数据之和的相反数,并对之排序,然后利用二分法进行查找即可. [AC代码] #include<iostream> #include<algorithm> using namespace std; int n,ans,a[4040],b[4040],c[4

poj 2785 4 Values whose Sum is 0 哈希

题意: 给4个集合ABCD,问有多少种从中各取一个数和为0的方案. 分析: 枚举前两个数建哈希表,枚举后两个数查找即可. 代码: //poj 2785 //sep9 #include <iostream> using namespace std; const int maxN=4012; const int maxM=3999972; int a[maxN],b[maxN],c[maxN],d[maxN]; int hash[maxM+10]; int e; struct Edge { int

poj1840 Eqs(hash+折半枚举)

Description Consider equations having the following form: a1x13+ a2x23+ a3x33+ a4x43+ a5x53=0 The coefficients are given integers from the interval [-50,50]. It is consider a solution a system (x1, x2, x3, x4, x5) that verifies the equation, xi∈[-50,

Load Balancing 折半枚举大法好啊

Load Balancing 给出每个学生的学分.   将学生按学分分成四组,使得sigma (sumi-n/4)最小.         算法:   折半枚举 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <string> 7 #include <