题目描述
有 5 个整数 a,b,c,d,e ,均在 [−50,50] 中,求满足
a×x31+b×x32+c×x33+d×x34+e×x35=0的正整数组合 {x1,x2,x3,x4,x5} 的个数。
其中任意的 x 不能等于0。
输入格式 1812.in
一行 5 个数,分别是
a,b,c,d,e 。
输出格式 1812.out
一个整数表示正整数组合的个数。
输入样例 1812.in
37 29 41 43 47
输出样例 1812.out
654
既然是要解方程,给定了系数,最显然(但也是最暴力)的做法就是枚举每一个
x
,然后检查、计数。时间复杂度显然是
进一步思考,如果将方程变形得到
a×x31+b×x32+c×x33+d×x34=−e×x35
其实就可以只枚举前四个
x
,进而确定 pow3[i]
标记是否有某个数的立方为 不过,这样还是很危险。
其实我们完全可以利用类似的思想,还是将方程变形,得到
a×x31+b×x32+c×x33=−(d×x34+e×x35)
如果我们能枚举前三个
x
,而且快速判断是否有 预处理嘛。
先枚举
x4
和
x5
,算出所有的
d×x34+e×x35
,hash 保存起来,再去枚举
x1
、
x2
和
x3
,在 hash 里面检查是否有满足要求的值即可。
但是要注意一个问题,这题可能会出现负数,因此要 hash 处理的时候要统一先加上一个大的偏移量。
由这题的不断优化我们应该归纳出一类方法,即分解任务的思想,在题目有一些限制的时候,尝试是否可以把它们拆分解决,有时候可以取得很好的效果。
参考代码:
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
const int prime = 23333;
struct Data {
int value, count;
Data () { value = count = 0; }
} hash[prime];
int a1, a2, a3, a4, a5;
void insert(int x) {
x += 23333333; //偏移量,使 hash 值变成非负数
int y = x % prime;
while (hash[y].value != x && hash[y].count) {
y += x % 1007 + 1;
if (y >= prime) y -= prime;
}
hash[y].value = x;
++hash[y].count;
}
int find(int x) {
x += 23333333;
int y = x % prime;
while (hash[y].value != x && hash[y].count) {
y += x % 1007 + 1;
if (y >= prime) y -= prime;
}
return hash[y].count;
}
int main(void) {
freopen("1812.in", "r", stdin);
freopen("1812.out", "w", stdout);
scanf("%d%d%d%d%d", &a1, &a2, &a3, &a4, &a5);
for (int x4 = -50; x4 <= 50; x4++)
if (x4) //注意 x 均不能为 0,下同
for (int x5 = -50; x5 <= 50; x5++)
if (x5) insert(a4 * x4 * x4 * x4 + a5 * x5 * x5 * x5);
int ans = 0;
for (int x1 = -50; x1 <= 50; x1++)
if (x1)
for (int x2 = -50; x2 <= 50; x2++)
if (x2)
for (int x3 = -50; x3 <= 50; x3++)
if (x3) ans += find(-(a1 * x1 * x1 *x1 + a2 * x2 * x2 * x2 + a3 * x3 * x3 * x3));
printf("%d\n", ans);
return 0;
}