HDU 4334 Trouble 贪心 或 哈希

Trouble
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5752 Accepted Submission(s): 1594

Problem Description

Hassan is in trouble. His mathematics teacher has given him a very difficult problem called 5-sum. Please help him.
The 5-sum problem is defined as follows: Given 5 sets S_1,…,S_5 of n integer numbers each, is there a_1 in S_1,…,a_5 in S_5 such that a_1+…+a_5=0?

Input

First line of input contains a single integer N (1≤N≤50). N test-cases follow. First line of each test-case contains a single integer n (1<=n<=200). 5 lines follow each containing n integer numbers in range [-10^15, 1 0^15]. I-th line denotes set S_i for 1<=i<=5.

Output

For each test-case output “Yes” (without quotes) if there are a_1 in S_1,…,a_5 in S_5 such that a_1+…+a_5=0, otherwise output “No”.

Sample Input

2
2
1 -1
1 -1
1 -1
1 -1
1 -1
3
1 2 3
-1 -2 -3
4 5 6
-1 3 2
-4 -10 -1

Sample Output

No
Yes

尝试用二分把前三个数组求和的话超内存了,换了一种思路。5个数组将4组求和化成2组,这样就有3个数组了,不会超内存,在小的数组中枚举数,用游标法在另外两个和数组中查找是否有对应值使和为0.

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<vector>
#include<math.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAX=200+2;
ll s1[MAX]={0};
ll s2[MAX]={0};
ll s3[MAX]={0};
ll s4[MAX]={0};
ll s5[MAX]={0};
ll s12[MAX*MAX]={0};
ll s45[MAX*MAX]={0};
bool cmp(ll a,ll b)
{
    return a<b;
}
int main()
{
    int T;
    int n;
    cin>>T;
    while(T--)
    {
        cin>>n;
        for (int i=0;i<n;i++) cin>>s1[i];
        for (int i=0;i<n;i++) cin>>s2[i];
        for (int i=0;i<n;i++) cin>>s3[i];
        for (int i=0;i<n;i++) cin>>s4[i];
        for (int i=0;i<n;i++) cin>>s5[i];
        int cnt1=0;
        for (int i=0;i<n;i++)
            for (int j=0;j<n;j++)
                    s12[cnt1++]=s1[i]+s2[j];
        int cnt2=0;
        for (int i=0;i<n;i++)
            for (int j=0;j<n;j++)
                s45[cnt2++]=s4[i]+s5[j];
        sort(s12,s12+cnt1,cmp);
        sort(s45,s45+cnt2,cmp);
        bool find=false;
        for (int i=0;i<n;i++)
        {
            int a=0;int b=cnt2-1;
            while (true)
            {
                if (s12[a]+s45[b]==-s3[i])
                {
                    find=true;
                    break;
                }
                else if (s12[a]+s45[b]>-s3[i])
                {
                    b--;
                    if (b<0) break;
                }
                else
                {
                    a++;
                    if (a>=cnt1) break;
                }
            }
            if (find)
                break;
        }
        if (find) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
}

哈希做法

#include<stdio.h>
#include<string>
#include<cstring>
#include<queue>
#include<algorithm>
#include<functional>
#include<vector>
#include<iomanip>
#include<math.h>
#include<iostream>
#include<sstream>
#include<stack>
#include<set>
#include<map>
using namespace std;
const int MAX = 733733;
typedef long long ll;
int T, N;
ll A[5][205];
ll F[MAX];
bool used[MAX];
int Hash(ll x)
{
    int p = x%MAX;
    if (p < 0) p += MAX;
    while (used[p] && F[p] != x)
        p = (p + 1) % MAX;
    return p;
}
int main()
{
    cin.sync_with_stdio(false);
    cin >> T;
    while (T--)
    {
        memset(used,0,sizeof(used));
        cin >> N;
        for (int i = 0; i < 5; i++)
            for (int j = 0; j < N; j++)
                cin >> A[i][j];
        for (int i=0;i<N;i++)
            for (int j = 0; j < N; j++)
            {
                ll sum = -(A[0][i] + A[1][j]);
                int pos = Hash(sum);
                F[pos] = sum;
                used[pos] = true;
            }
        bool Find = false;
        for (int i=0;i<N;i++)
            for (int j=0;j<N;j++)
                for (int k = 0; k < N; k++)
                {
                    ll sum = (A[2][i] + A[3][j] + A[4][k]);
                    int pos = Hash(sum);
                    if (used[pos])
                    {
                        Find = true;
                        i = N, j = N, k = N;
                    }
                }
        if (Find) cout << "Yes\n";
        else cout << "No\n";
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值