POJ2785 和爲0的組合數(數的哈希)

給定4個組合A,B,C,D,這四個組合裏面的元素數目相等。要求找出所有的序列(a, b, c, d),四個數分別來自A,B,C,D四個組合,使得a + b + c + d = 0,輸出這樣的序列的總數。若兩個滿足條件的序列是完全相同的,它們也算是不同的序列,因爲A,B,C,D中可能含有相同的元素。

解題思路很簡單,取所有的(a, b)序列進行哈希,以a+b作爲鍵,分別映射到非負數和負數兩個哈希表上,若有重複的(a, b),則只需要記錄次數,不需要再開闢結點存儲。

然後對所有的(c, d)序列,以c+d作爲鍵進行查找,若c+d爲正則查找對應的負數哈希表,若爲負則查找對應的非負數哈希表,把符合a+b+c+d=0的所有結點的所有次數相加就得到最後的答案了。

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

const int N = 9000005;
const int M = 4005;
const int H = 4000007;
int n;
long long ans;
int A[M], B[M], C[M], D[M];

struct Node
{
	int a;
	int b;
	int cnt;
	int next;
};
Node nodeP[N];
Node nodeN[N];
int curP, curN;
int hashTableP[H];
int hashTableN[H];

void initHash()
{
	for (int i = 0; i < H; ++i) hashTableP[i] = hashTableN[i] = -1;
	curP = curN = 0;
	ans = 0;
}

void searchHash(int& a, int& b)
{
	int h = (a + b) % H;
	int next;
	if (h >= 0) 
	{
		next = hashTableP[h];
		while (next != -1)
		{
			if (a == nodeP[next].a && b == nodeP[next].b) 
			{
				++nodeP[next].cnt;
				return;
			}
			next = nodeP[next].next;
		}
		nodeP[curP].a = a;
		nodeP[curP].b = b;
		nodeP[curP].cnt = 1;
		nodeP[curP].next = hashTableP[h];
		hashTableP[h] = curP;
		++curP;
	}
	else
	{
		h = -h;
		next = hashTableN[h];
		while (next != -1)
		{
			if (a == nodeN[next].a && b == nodeN[next].b) 
			{
				++nodeN[next].cnt;
				return;
			}
			next = nodeN[next].next;
		}
		nodeN[curN].a = a;
		nodeN[curN].b = b;
		nodeN[curN].cnt = 1;
		nodeN[curN].next = hashTableN[h];
		hashTableN[h] = curN;
		++curN;
	}
}

void getAns(int& c, int& d)
{
	int h = (c + d) % H;
	int next;
	if (h > 0)
	{
		next = hashTableN[h];
		while (next != -1)
		{
			if (nodeN[next].a + nodeN[next].b + c + d == 0) ans += nodeN[next].cnt;
			next = nodeN[next].next;
		}
	}
	else
	{
		h = -h;
		next = hashTableP[h];
		while (next != -1)
		{
			if (nodeP[next].a + nodeP[next].b + c + d == 0) ans += nodeP[next].cnt;
			next = nodeP[next].next;
		}
	}
}

int main()
{
	initHash();
	scanf("%d", &n);
	for (int i = 0; i < n; ++i) scanf("%d%d%d%d", &A[i], &B[i], &C[i], &D[i]);
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < n; ++j)
		{
			searchHash(A[i], B[j]);
		}
	}
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < n; ++j)
		{
			getAns(C[i], D[j]);
		}
	}
	printf("%lld\n", ans);
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章