Eqs 源自罗马尼亚2002年信息学竞赛------------五元三次方程求解
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;
}
\