1.题目描述:点击打开链接
2.解题思路:本题利用Hash技术+双向查找解决。可以先计算出a*x0*x0+b*x1*x1的所有可能结果,然后再查找-(c*x2*x2+d*x3*x3)的个数,由于每个值都有2种情况,因此一共有16种组合,最终统计出个数后还要乘以16。存储前一半的所有可能的结果可以有多种方法,可以使用STL中的set或者multiset,也可以自己写一个Hash函数,将所有结果和一个Hash值对应(不一定是一一对应)然后用对应的Hash数组来统计个数,为了防止出现不同的sum对应相同的Hash值,还要额外开一个数组来判重。
网上很多题解是将结果+10^6后存起来,但是数组的空间浪费比较大。由于只是二重循环,最多只有100*100个不同的结果,因此只需要考虑设计一个Hashsize大于10^4的数组即可,如果发生Hash值冲突时,可以进行再散列,即不断地向右移动,看是否有别的空位可以使用。可以保证一定可以找到合适的空位来存储新的结果。但是为了减少冲突的处理,可以将Hashsize设置为所有可能结果数量的4倍或5倍。详细过程见代码。
3.代码:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<functional>
using namespace std;
#define me(s) memset(s,0,sizeof(s))
#define pb push_back
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <int, int> P;
const int M=40021;//为了减少冲突的处理,设置为所有结果数量的4倍
int f[M],g[M];//f[i]表示哈希值为i的结果的个数;g[i]表示哈希值为i对应的和sum,起到判重的作用
int t[110];
int Hash(int k)
{
int t=(k%M+M)%M;
while(f[t]&&g[t]!=k)//当发生冲突时,不断地向右移动t,看是否有空位或者其他哈希值和k相同的位置可以用
t=(t+1)%M;
return t;
}
int main()
{
int a,b,c,d,s,p,n;
for(int i=1;i<101;i++)
t[i]=i*i;
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)
{
printf("0\n");continue;
}
me(f);me(g);
n=0;
for(int i=1;i<=100;i++)
for(int j=1;j<=100;j++)
{
s=a*t[i]+b*t[j];
p=Hash(s);
g[p]=s;
f[p]++;
}
for(int i=1;i<=100;i++)
for(int j=1;j<=100;j++)
{
s=-(c*t[i]+d*t[j]);
p=Hash(s);
n+=f[p];
}
printf("%d\n",n*16);
}
}