http://acm.hdu.edu.cn/showproblem.php?pid=4334
http://acm.hdu.edu.cn/showproblem.php?pid=1496
多校联合赛中的一道题,听了洛神的讲解才了解到关于hash的思想,然后自己写了一下,非常爽,效率相当的高啊。。
思路:创建一个大数组,将五组数分为两组,一组为2,一组为3,求出其中一组的数通过hash函数保存在大数组里面,在计算出另一组的结果,也通过hash函数,与数组中保存的结果进行比较
关键:尽量减少冲突,提高效率
hash函数
int Hash(__int64 k)
{
__int64 p,i;
p=k%N;
if(p<0)
p+=N;
while(flag[p]&&hash[p]!=k) //
{
p=(p+1)%N;
}
return p;
}
如果为负数的话,取模后在加上一个大数N
插入时,如果flag[p]==0的话,表示hash[p]处还没有储存有值,就把k储存在此处,如果k已将存在就不再存,如果flag[p]==1的话,就向后寻找未储存的(如果一直到结尾都没有找到,就从开头再开始找)
寻找时,如果flag[p]==1的话,就向后寻找,一直到找到k,如果碰到flag[]==0说明不存在k,如果flag[p]==0的话,k肯定不存在,直接结束
AC代码
#include<stdio.h>
#include<string.h>
#define N 400005
__int64 a[5][205];
__int64 hash[N];
bool flag[N];
int Hash(__int64 k)
{
__int64 p,i;
p=k%N;
if(p<0)
p+=N;
while(flag[p]&&hash[p]!=k) //
{
p=(p+1)%N;
}
return p;
}
int main()
{
int t,n,i,j,l,p;
scanf("%d",&t);
while(t--)
{
memset(flag,0,sizeof(flag));
scanf("%d",&n);
for(i=0;i<5;i++)
for(j=0;j<n;j++)
scanf("%I64d",&a[i][j]);
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
p=Hash(a[0][i]+a[1][j]);
hash[p]=a[0][i]+a[1][j];
flag[p]=1;
}
for(i=0;i<n;i++)
for(j=0;j<n;j++)
for(l=0;l<n;l++)
{
p=Hash(-(a[2][i]+a[3][j]+a[4][l]));
if(flag[p])
{
printf("Yes\n");
goto z;
}
}
printf("No\n");
z:;
}
return 0;
}
1496 AC 代码
#include<stdio.h>
#include<string.h>
#define N 5000000
int hash[N],flag[N];
int Hash(int k)
{
int p;
p=k%N;
if(p<0) p+=N;
while(flag[p]&&hash[p]!=k)
p=(p+1)%N;
return p;
}
int main()
{
int a,c,b,d,i,j,p,count;
while(~scanf("%d%d%d%d",&a,&b,&c,&d))
{
if(a>0&&b>0&&c>0&&d>0||a<0&&b<0&&c<0&&d<0)
{ printf("0\n");
continue;
}
memset(flag,0,sizeof(flag));
count=0;
for(i=1;i<=100;i++)
for(j=1;j<=100;j++)
{
p=Hash(a*i*i+b*j*j);
hash[p]=a*i*i+b*j*j;
flag[p]++;
}
for(i=1;i<=100;i++)
for(j=1;j<=100;j++)
{
p=Hash(-(c*i*i+d*j*j));
if(flag[p])
count+=flag[p];
}
printf("%d\n",count<<4);
}
return 0;
}