HDU 1496 Equations

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);
    }
}


你可能感兴趣的:(计数,hash,哈希技术)