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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值