Eqs 源自罗马尼亚2002年信息学竞赛------------五元三次方程求解

83 阅读3分钟

Eqs 源自罗马尼亚2002年信息学竞赛------------五元三次方程求解

给出POJ链接

Cubic Equation

发布时间: 2016年9月13日 17:57   最后更新: 2016年9月28日 22:33   时间限制: 1000ms   内存限制: 64M

描述

考虑如下形式的方程:

a*x1^3+b*x2^3+c*x3^3+d*x4^3+e*x5^3=0

其中系数a, b, c, d, e是[-50, 50]的整数。

求满足方程的解(x1, x2, x3, x4 ,x5)的个数,其中xi是[-50, 50]的非零整数。

输入

五个以空格分隔的整数作为方程系数a, b, c, d, e。

输出

一个整数,表示方程的解的个数。若a=b且(x1, x2, x3, x4 ,x5)是解,则(x2, x1, x3, x4 ,x5)计数时视作与(x1, x2, x3, x4 ,x5)不同的解。

样例输入1  复制

37 29 41 43 47

样例输出1

654

提示

解最多的情况是多少?小心TLE和MLE!

这道题肯定是不能用用四重循环瞎搞的,计算10^8次肯定超时。网上很多说把a*x1^3+b*x2^3+c*x3^3+d*x4^3+e*x5^3=0 

变形为 -(a*x1^3 + b*x2^3) = c*x3^3 + d*x4^3 + e*x4^3。为什么好多人都想到了这个方法?但有些人写的代码显然是有缺陷的,虽然能在POJ1840上通过,可能是后台测试数据不足。

\

大概思想:用2重循环得到等式左边的所有可能值,负数加上个足够大的正数,然后负数就化身(hash值)为了一个正数(有些像计算机中的补码吧)。且化身的正数不能和立方和正数重叠,所以最大值设为 50 * 50 * 50 * 50 * 4.可能是不合理的。因为-125 00000 + 2500 0000 = 1250 0000,而 50 * 50 * 50 * 50 * 2 = 1250 0000.(化身和立方和撞衫了,分不清谁是谁了)。

还有当变形后的等式右边立方和值大于1250 0000.时,在等式左边的立方和值是不可能大于这个数的,这时显然是没有可行解的。网上的AC代码中并没有这个判断,直接累加 hash[右值],这个右值可能对应左边的负数的hash值,且对应右边的立方和。这能直接累加吗?

\

下面是我的在POj1840过了的代码,但是在神秘OJ一直错,不知道为啥(有6个人过了,说明测试数据没错)。

#include <cstdio> 
#include <cstring>
const int N = 50, MAX = N * N * N * N * 4 + 1;
short hashV[MAX + 7]; //类似于补码的思想,把负数映射为正数 
int main()
{
	int a, b, c, d, e;
	while(scanf("%d%d%d%d%d", &a, &b, &c, &d, &e) == 5) {
		memset(hashV, 0, sizeof hashV);
		for (int i = -N; i <= N; ++i) {
			if(i == 0) continue;
			int aiii = a * i * i * i;
			for (int j = -N; j <= N; ++j) {
				if(j == 0) continue;
				int left = -(aiii + b * j * j * j);
				if(left < 0) left = left + MAX;
				hashV[left]++; 
			}
		}
		int res = 0;
		for (int i = -N; i <= N; ++i) {
			if(i == 0) continue;
			int ciii = c * i * i * i;
			for(int j = -N; j <= N; ++j) {
				if(j == 0) continue;
				int ciii_djjj = ciii + d * j * j * j;
				for (int k = -N; k <= N; ++k) {
					if(k == 0) continue;
					int right = ciii_djjj + e * k * k * k;
					if(right > MAX / 2) continue;
					if(right < 0) right += MAX;
					res += hashV[right]; 
				}
			}
		}
		printf("%d\n", res);
	}
	
	return 0;
}



\