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; }