[SMOJ1812]解方程

来源:互联网 发布:淘宝买家好评率查询网 编辑:程序博客网 时间:2024/06/05 11:22

题目描述

有 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,然后检查、计数。时间复杂度显然是 O(n5) 的,本题中每个 x 的取值范围都有 100,那么就是 1010,显然是不可行的。

进一步思考,如果将方程变形得到

a×x31+b×x32+c×x33+d×x34=e×x35
其实就可以只枚举前四个 x,进而确定 x5。但是还要开立方,比较麻烦,不过 x 比较小,可以通过预处理一个 bool 数组,pow3[i] 标记是否有某个数的立方为 i,这样就可以实现 O(1) 判断,总的复杂度是 108 左右,似乎是可行的。

不过,这样还是很危险。
其实我们完全可以利用类似的思想,还是将方程变形,得到

a×x31+b×x32+c×x33=(d×x34+e×x35)
如果我们能枚举前三个 x,而且快速判断是否有 x4x5 满足方程,就可以在 106 的时间内完成任务。关键在于,方程左边代入计算得到一个值之后,取它的相反数,如何判断是否有 x4x5 能得到它呢?

预处理嘛。
先枚举 x4x5,算出所有的 d×x34+e×x35,hash 保存起来,再去枚举 x1x2x3,在 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;}
0 0
原创粉丝点击