给定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;
}