Uva 1152 和为0的4个值 hash/二分

来源:互联网 发布:口袋妖怪游戏作弊软件 编辑:程序博客网 时间:2024/05/16 19:20

题意:
给定4个n(1 <= n <= 4000)元素集合A, B, C, D,要求分别从中选取一个元素a, b, c, d,使得a+b+c+d = 0,问有多少种选法。
分析:
显然四重循环是过不了的,我先想到的是用map把a+b,c+d分别保存起来,然后在查找统计。超时。。。。
然后书上说用哈希表去实现,看到有的题解hash表示的太巧妙了,学习一下。
还有就是这题可以用二分解决,先计算出a+b,然后枚举c+d,然后二分找出范围即可。

hash 630ms:

#include<cstdio>#include<cstring>const int N=4005;int a[4][N];struct Hash_map{    static const int mask=0x7fffff;    int p[mask+1],q[mask+1];    void clear()    {        memset(q,0,sizeof(q));    }    int& operator [](int k)    {        int i;        for(i=k&mask;q[i]&&p[i]!=k;i=(i+1)&mask);        p[i]=k;        return q[i];    }};Hash_map Hash;int main(){    int T;scanf("%d",&T);    for(int t=0;t<T;t++){        int n;        scanf("%d",&n);        for(int j=0;j<n;j++)            for(int i=0;i<4;i++)scanf("%d",&a[i][j]);        Hash.clear();        for(int i=0;i<n;i++)            for(int j=0;j<n;j++)            Hash[a[0][i]+a[1][j]]++;        int ans=0;        for(int i=0;i<n;i++)            for(int j=0;j<n;j++)            ans+=Hash[-a[2][i]-a[3][j]];        if(t)printf("\n");        printf("%d\n",ans);    }    return 0;}

二分 、2720ms:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int N=4005;int a[4][N];int sum[N*N];int main(){    int T;scanf("%d",&T);    for(int t=0;t<T;t++){        int n;        scanf("%d",&n);        for(int j=0;j<n;j++)            for(int i=0;i<4;i++)scanf("%d",&a[i][j]);        int cnt=0;        for(int i=0;i<n;i++)            for(int j=0;j<n;j++)            sum[cnt++]=a[0][i]+a[1][j];        int ans=0;        sort(sum,sum+cnt);        for(int i=0;i<n;i++)            for(int j=0;j<n;j++)            ans+=upper_bound(sum,sum+cnt,-a[2][i]-a[3][j])-lower_bound(sum,sum+cnt,-a[2][i]-a[3][j]);        if(t)printf("\n");        printf("%d\n",ans);    }    return 0;}
0 0
原创粉丝点击