NKOJ-3704 解方程

P3704解方程
时间限制 : - MS 空间限制 : 65536 KB
评测说明 : 时限1000ms

问题描述
告诉你A1,A2,A3,A4,A5,计算出下面方程在[-50,50]内的解的数量:
A1*X1^3+ A2*X2^3+ A3*X3^3+ A4*X4^3+ A5*X5^3=0
要求Xi!=0

输入格式
一行,5个空格间隔的整数,表示A1,A2,A3,A4,A5

输出格式
一个整数,表示解的个数

样例输入
37 29 41 43 47

样例输出
654

提示
-50<=Ai<=50
-50<=Xi<=50且Xi!=0

来源 Romania OI 2002

据说要用哈希

但其实用哈希很虚,因为解与解之间有可能重复(详情见后)
而且我曾经立下毒誓,以后绝对不会用哈希

解题吧…

这道题目其实是很暴力的
但是不能盲目暴力
暴力是要讲究方法的

所以叠五层循环的智障方法我们就不讲了

因此我们只叠2+3层(很明显的暴力优化)
(看到这里不知道你们有没有思路,如果有的话就自己再去做一次,毕竟自己想出来的总是好很多)

方程变形,左边放两个未知数,右边放三个

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

然后暴力枚举x1,x2,记录左边的值(mark数组记录)
然后再暴力枚举x3,x4,x5,寻找右边的值在mark数组当中的值,加进res里头
然后就求出来啦!!

注意

①左边的值是很有可能重复的(毕竟二元),所以mark数组记录的不是这个数字存在与否,而是出现的次数,因此不能用bool,但是又不能爆空间,所以建议用short(可能char也可以吧)
②开数组的大小问题

因为右边的值一定要等于左边的值,所以我们只需要考虑左边的值的取值范围
    于是我们就有了50*50*50*50,但这只是a从1到50的,为了避免负数的情况,我们需要*2(因为负数>=-50*50*50*50,通过加50*50*50*50的可以避免)
    因为有两个数所以再*2
    结果就是25000000,这就是mark数组的大小(要稍微开大一点点)

③有个小细节,虽然我不说应该都能够通过跑样例得出,但还是说一下
就是题目当中加黑了的x!=0(需要特判)

就是这样了

是不是很暴力

附上代码

#include <iostream>
#include <cstdio>
using namespace std;

short mk[25001234];
int res=0;
int a,b,c,d,e;

int main()
{
    scanf("%d%d%d%d%d",&a,&b,&c,&d,&e);
    for(int xd=-50;xd<51;xd++)
        for(int xe=-50;xe<51;xe++)
            mk[-xd*xd*xd*d-xe*xe*xe*e+12500000]++;
    for(int xa=-50;xa<51;xa++)
        for(int xb=-50;xb<51;xb++)
            for(int xc=-50;xc<51;xc++)
            {
                add=xa*xa*xa*a+xb*xb*xb*b+xc*xc*xc*c;
                if(mk[add])res+=mk[add];
            }
    printf("%d",res);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值