标签:
题意:
给定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;
}
标签:
原文地址:http://blog.csdn.net/hjt_fathomless/article/details/51361652