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