hdu 1496 Equations (整数Hash)

给定a、b、c、d,问a*x1^2+b*x2^2+c*x3^2+d*x4^2=0的在[-100,100]上非0解的个数


直接枚举会超时。

将等式变换一下:a*x1^2+b*x2^2=-(c*x3^2+d*x4^2)

预先枚举x1,x2,计算等式左边可能出现的值,然后枚举x3,x4,计算等式右边的值,看之前是否出现过该值,结果累加该值出现次数即可。


由于值可能为负数,需要处理一下。

简单的方法是直接使用map来映射之前出现过的值以及对应次数,当然这样做效率不是很高。

另一种做法是,考虑参数的范围是[-50,50],因此值的绝对值不会超过2*50*100^2=10^6,将得到的值均加上一个10^6,这样便将负数转换为正数。

然后构建Hash函数来记录值和次数的对应关系。Hash表的大小为2*10^6

当然,空间复杂度还是可以优化的,比如使用除留余数法来建立哈希函数,使用线性探测再散列方法进行冲突处理。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 40001
int H[maxn],num[maxn];

int Hash(int x)
{
    int p=x;
    p%=maxn;
    if(p<0) p+=maxn;
    while(num[p]!=0&&H[p]!=x) p=(p+1)%maxn;
    return p;
}

int main()
{
    int a,b,c,d;
    while(~scanf("%d%d%d%d",&a,&b,&c,&d))
    {
        if((a>0&&b>0&&c>0&&d>0)||(a<0&&b<0&&c<0&&d<0))
        {
            puts("0");
            continue;
        }
        memset(num,0,sizeof(num));
        int tmp,p,i,j,ans=0;
        for(i=1;i<=100;++i)
            for(j=1;j<=100;++j)
            {
                tmp=i*i*a+j*j*b;
                p=Hash(tmp);
                H[p]=tmp;
                num[p]++;
            }
        for(i=1;i<=100;++i)
            for(j=1;j<=100;++j)
            {
                tmp=-(i*i*c+j*j*d);
                p=Hash(tmp);
                ans+=num[p];
            }
        printf("%d\n",ans*16);
    }
    return 0;
}


你可能感兴趣的:(hdu 1496 Equations (整数Hash))