Come On For My Dream

导航

POJ1186 方程的解数

人生第四道ACM题,学习到了开散列法。又写了两天时间,菜鸟就是菜鸟啊,什么都不会!

这已经是我目前做过最变态的一道了(前三道绝对没有这么复杂),写了87行啊有木有!英文题看不懂,所以老翻中文题做,但是中文题确实不好惹啊!!!不过所幸是一次提交就AC的,在这里给自己加油,鼓励自己一定要坚持下去!

这道题就是要求一个n元高次方程的解的个数,由于最多有6项,并且限制x的范围是1~150,所以总共的状态数有150^6 = 11390625000000,太多了。考虑把一半项移到右边,然后先对左边每一个Xi枚举求值并进行hash,全部求完后,再对右边进行枚举计算求值并检查该值是否在hash表中,如果有就加上左边得到这个值的状态数,没有就不管,然后就AC了,泪奔~~~

#include <iostream>
#include <cmath>
using namespace std;

const int STATUS = 3375010;
const int P = 611953;
int Slots[P], Nxt[STATUS], Key[STATUS], Val[STATUS], EN;
int M, k[6], p[6], s;

void hash(int key)
{
	int e, pos = (key % P + P) % P;
	e = Slots[pos];
	while (e != -1) {
		if (Key[e] == key) {
			Val[e]++;
			return;
		}
		e = Nxt[e];
	}
	Val[EN] = 1;
	Key[EN] = key;
	Nxt[EN] = Slots[pos];
	Slots[pos] = EN++;
}

void cal(int key)
{
	int e, pos = (key % P + P) % P;
	e = Slots[pos];
	while (e != -1) {
		if (Key[e] == key) {
			s += Val[e];
			return;
		}
		e = Nxt[e];
	}
}

bool check_k(int l, int h) 
{
	while (l <= h) {
		if (k[l++] != 0) 
			return false;
	}
	return true;
}

void generate(int mod, int l, int h, int sum)
{
	if (l > h) {
		if (mod == 1) hash(sum);
		else cal(-sum);
		return;
	}
	for (int x = 1; x <= M; ++x) {
		generate(mod, l + 1, h, sum + k[l]*(int)pow(double(x), p[l]));
	}
}

int main()
{
	int i, j, n;
	while (cin >> n >> M) {
		for (i = 0; i < n; i++) {
			cin >> k[i] >> p[i];
		}
		for (EN = i = 0; i < P; i++) {
			Slots[i] = -1;
		}
		if (check_k(0, n - 1)) {
			s = 1;
			for (i = 0; i < n; i++) {
				s *= M;
			}
			cout << s << endl;
			continue;
		}
		if (check_k(0, (n + 1) / 2 - 1)) hash(0);
		else generate(1, 0, (n + 1) / 2 - 1, 0);
		s = 0;
		if (check_k((n + 1) / 2, n - 1)) cal(0);
		else generate(2, (n + 1) / 2, n - 1, 0);
		cout << s << endl;
	}
	return 0;
}

posted on 2011-07-20 15:37  ComeOn4MyDream  阅读(664)  评论(0编辑  收藏  举报