POJ 1840 Eqs(双向DFS)

Description
有如下方程: a 1 x 1 3 + a 2 x 2 3 + a 3 x 3 3 + a 4 x 4 3 + a 5 x 5 3 = 0 a_1x_1^{3}+a_2x_2^{3}+a_3x_3^{3}+a_4x_4^{3}+a_5x_5^{3}=0 a1x13+a2x23+a3x33+a4x43+a5x53=0
系数: a 1 , . . . , a 5 ∈ [ − 50 , 50 ] a_1,...,a_5 \in [-50, 50] a1,...,a5[50,50]
未知数: x 1 , . . . , x 5 ∈ [ − 50 , 50 ] , x i = ̸ 0 , a n y   i ∈ 1 , 2 , 3 , 4 , 5 x_1,...,x_5 \in [-50,50],x_i =\not0,any \ i \in{1,2,3,4,5} x1,...x5[50,50],xi≠0,any i1,2,3,4,5
求满足方程得解的个数

Input
输入 a1, a2, a3, a4, a5, separated by blanks.

Output
方程解的个数

Sample Input
37 29 41 43 47

Sample Output
654

思路: 每个未知数有100种可能,对每个未知数直接枚举则时间复杂度为O(100^5),在这题会超时。遇到这种指数级复杂度,且底数比较大的可以使用meet in the middle来降低时间复杂度。

meet in the middle的做法是将5个未知数分为两组,第一组为 x 1 , x 2 x_1,x_2 x1,x2,第二组为 x 3 , x 4 , x 5 x_3,x_4,x_5 x3,x4,x5
对第一组未知数的每种可能进行枚举,计算出 s u m 1 = a 1 x 1 3 + a 2 x 2 3 sum1 = a_1x_1^{3}+a_2x_2^{3} sum1=a1x13+a2x23,将sum1存入哈希表dic中(哈希表的key为sum1,value为sum1出现的次数),之后枚举第二组未知数,计算 s u m 2 = a 3 x 3 3 + a 4 x 4 3 + a 5 x 5 3 sum2 = a_3x_3^{3}+a_4x_4^{3}+a_5x_5^{3} sum2=a3x33+a4x43+a5x53,在哈希表dic中得到第一组枚举结果为-sum2(sum1+sum2=0移项得到)出现的次数dic[-sum2],此时sum1+sum2=0。记录方程的解的数量ans+=dic[-sum2]。

这题使用STL的map会超时,可以自己构建一个足够大的数组模拟哈希表。
sum1的可能范围为[-12500000, 12500000],我们创建一个哈希表

#define MAX_NUM 25000000
short hsh[MAX_NUM+10];

计算sum1:int sum1 = a1*x1*x1*x1 + a2*x2*x2*x2; 因为我们是用数组下标作为key(sum1),而数组下标不能为负数,所以我们把sum1加上一个数,使得所有的sum1都为正数,并且将该下标数组内的值加一

hsh[sum1 + 12500000]++;//[-12,500,000, 12,500,000]->[0, MAX_NUM]

最后计算出sum2时:int sum2 = a3*x3*x3*x3 + a4*x4*x4*x4 + a5*x5*x5*x5; 我们并不是直接去哈希表里找-sum2的内容,因为此时方程其实可以看成sum1+12500000 + sum2 - 12500000 = 0,移项,将第一组枚举的结果放在方程左边得到:sum1 + 12500000 = 12500000 - sum2。所以我们需要在哈希表里找12500000 - sum2的内容,这样加起来结果就为0了。

if (hsh[-sum2 + 12500000])//hsh[-sum + 12500000]为枚举x1, x2时,sum1等于-(sum2)的次数
    res += hsh[-sum2 + 12500000];//如果这个次数不为零加上由x3,x4,x5产生的sum2结果为0,所以将这个次数累加到res

代码:

#include <iostream>
using namespace std;

#define MAX_NUM 25000000
short hsh[MAX_NUM+10];

int main()
{
	int a1, a2, a3, a4, a5, res = 0;
	cin>>a1>>a2>>a3>>a4>>a5;
	for (int x1 = -50; x1 <= 50; x1++)
	{
		if (x1 == 0) continue;
		for (int x2 = -50; x2 <= 50; x2++)
		{
			if (x2 == 0) continue;
			int sum = a1*x1*x1*x1 + a2*x2*x2*x2;//
			hsh[sum + 12500000]++;//[-12,500,000, 12,500,000]->[0, MAX_NUM]
		}
	}

	for (int x3 = -50; x3 <= 50; x3++)
	{
		if (x3 == 0) continue;
		for (int x4 = -50; x4 <= 50; x4++)
		{
			if (x4 == 0) continue;
			for (int x5 = -50; x5 <= 50; x5++)
			{
				if (x5 == 0) continue;
				int sum = a3*x3*x3*x3 + a4*x4*x4*x4 + a5*x5*x5*x5;
				if (sum < -12500000 || sum > 12500000) continue;
				if (hsh[-sum + 12500000])
					res += hsh[-sum + 12500000];
			}
		}
	}
	cout<<res<<endl;
	return 0;
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值