HDU 4334 Trouble(Hash)

来源:互联网 发布:ubuntu安装了微信 编辑:程序博客网 时间:2024/06/11 13:16

题目链接:Click here~~

比赛时的一道题,当时没有好的思路,听学长讲了讲才知道可以用Hash做,之前用Hash只写过那个找球号的题。

题意:

有5组数,每组有n个,问能否在每组中找到一个数,令这5个数之和为0。

解题思路:

先用O(n^2)的时间求出前两组数的所有组合情况,将它们存入一个Hash表。

然后用O(n^3)的时间求出后三组数的所有组合情况,每求出一种就看下它的相反数是否在Hash表中出现。

之所以可以这样做,是因为Hash可以在大约常数时间内判断出一个数是否在Hash表中出现。Orz。


PS:

Hash函数用的是取模,性价比还行,用别的貌似更慢。

注意负数的处理,我开始是转成绝对值,1500+MS,看了学长的,他是+MAX,改成这个,果然快了,1300+MS。

Hash表的大小开10倍就行。开20倍与10倍时间基本没差距。


#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;typedef __int64 LL;#define FileIn  freopen("in.ads","r",stdin)#define FileOut freopen("out.ads","w",stdout)#define MAX 400005LL s[5][205];LL Hash[MAX];bool used[MAX];int hash(LL x){    int h = x % MAX;    if(h < 0)        h += MAX;    while(used[h] && Hash[h] != x)        h = (h+1) % MAX;    return h;}int main(){    int z,n;    scanf("%d",&z);    while(z--)    {        bool no = true;        memset(used,false,sizeof(used));        scanf("%d",&n);        for(int i=0;i<5;i++)            for(int j=0;j<n;j++)                scanf("%I64d",&s[i][j]);        for(int i=0;i<n;i++)            for(int j=0;j<n;j++)            {                LL sum = - (s[0][i] + s[1][j]);                int h = hash(sum);                used[h] = true;                Hash[h] = sum;            }        for(int i=0;i<n;i++)            for(int j=0;j<n;j++)                for(int k=0;k<n;k++)                {                    LL sum = s[2][i] + s[3][j] + s[4][k];                    int h = hash(sum);                    if(used[h])                    {                        no = false;                        goto bingo;                    }                }bingo:  puts(no?"No":"Yes");    }return 0;}


原创粉丝点击