HDU 4334 Trouble 和 HDU 1496 Equations( hash)

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




 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值