hash的基础思想:
1.哈希表(散列表)的基本原理:
使用一个下标范围比较大的数组来存储元素,一般通过设计一个函数(哈希函数,即散列函数),使得每个元素的关键字都与一个函数值(即数组下标)相对应,然后用该数组单元来存储对应元素。
2.hash表函数的构造:
最常见的方法:除余法
H(k ) = k mod p (p一般选取适当大的素数)
3.处理冲突
由于不能够保证每个元素的关键字与函数值是一一对应的,因此很有可能出现如下情况:“对于不同的元素关键字,Hash函数计算出了相同的函数值”,这就是产生了所谓的“冲突”。
换句话说,就是Hash函数把不同的元素分在了相同的下标单元。
常用方法:线性探测再散列技术
即:当 h(k)位置已经存储有元素的时候,依次探查 (h(k)+i) mod S, i=1,2,3…,直到找到空的存储单元为止。其中, S为 数组长度。
特别地,如果将数组扫描一圈仍未发现空单元,则说明哈希表已满,这会带来麻烦,但是,该情况完全可以通过扩大数组范围来避免。
4.hash表的基本操作
Hash表初始化(0或-1或其它)
哈希函数运算
插入元素(包含冲突解决)
定位(需考虑可能冲突的情况)
——————————————————————————————————————————————————————————
题意:
方程式为a*x1^2+b*x2^2+c*x3^2+d*x4^2=0
a, b, c, d 是 [-50,50] 区间内非零整数.
( x1,x2,x3,x4 ) 是[-100,100]区间内的非零整数。
问的是方程的解的情况有几种。
思路分析:
hash的妙处就在于实现了每一个元素的关键值都和数组的下标相对应。
先对x1和x2进行枚举,存在的存进hash表中,然后接下来枚举x3和x4,如果恰好和前面的为相反数,那么ans+上前面出现的次数.
由于求[-100,100]之间的非零整数,也就是说100*100*2=20000的一维数组就可以了。
PS:
用枚举1~100而负半区域不考虑,节省枚举数,最后答案因为四个数全部都是正的,而实际上都有每个数都有正有负,故答案*16
#include <stdio.h>
#include <algorithm>
#include <string.h>using namespace std;const int N = 2000005;int main()
{// freopen("in.txt", "r", stdin);int a, b, c, d;int Hash[N];while(~scanf("%d%d%d%d", &a, &b, &c, &d)){if(a * b > 0 && b * c > 0 && c * d > 0){printf("0\n");continue;}memset(Hash, 0, sizeof(Hash));for(int i = 1; i <= 100; i ++)for(int j = 1; j <= 100; j ++)Hash[a * i * i + b * j * j + 1000000] ++;int ans = 0;for(int i = 1; i <= 100; i ++)for(int j = 1; j <= 100; j ++)ans += Hash[- c * i * i - d * j * j + 1000000];printf("%d\n", 16 * ans); //我们计算的全是真的,实际上还有负的,只要在原结果*16即可。}return 0;
}