HDU 4334 Trouble

Trouble

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6911    Accepted Submission(s): 1927


 

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

 

 

Source

2012 Multi-University Training Contest 4

 

之前见过一道类似的题目,但是那题只有三个集合,当时用的是二分,将两个数组a, b相加组成一个新的数组A,之后再在A上二分找能够和c中的数符合条件的值。这题也类似,a,b相加组成s1,c,d组成s2,然后将其中一个排序,比如对s1排序,然后用二重循环再对s2和d中的数组合,再去s1中二分查找能够满足要求的数。复杂度O(n^3*logn),题目时间要求不高,能过。

 

还有一种解法是利用贪心。先利用分治思想,处理前两个集合的和s1,3 4集合的和s2。然后要介绍一种尺取法(也就是一种贪心思想):如何快速判断是否有A[i]+B[j]=x,先将A,B送小到大排序得到有序序列,可以先让i指向A数组的首指针,j指向B数组的为指针,判断A[i]+B[j]与x的大小关系,若A[i]+B[j]>x则j–;若A[i]+B[j]< x则i++。这样就可以在线性时间内判断是否A[i]+B[j]=x。最后复杂度是O(n^3)

#include <cstdio>
#include <algorithm>
#define ll long long
const int Max1 = 205, Max2 = 40005;
ll S1[Max1], S2[Max1], S3[Max1], S4[Max1], S5[Max1], SS1[Max2], SS2[Max2];
int N, n;

bool binarySearch(int i, int h)
{
    int l = 0, mid;
    while(l <= h)
    {
        mid = (l + h)>>1;
        if(SS2[mid] == i)    return true;
        else if(SS2[mid] < i)    l = mid + 1;
        else h = mid - 1;
    }
    return false;
}


int main()
{
    scanf("%d", &N);
    while(N--)
    {
        scanf("%d", &n);
        for(int i = 0; i < n; i++)    scanf("%lld", S1+i);
        for(int i = 0; i < n; i++)    scanf("%lld", S2+i);
        for(int i = 0; i < n; i++)    scanf("%lld", S3+i);
        for(int i = 0; i < n; i++)    scanf("%lld", S4+i);
        for(int i = 0; i < n; i++)    scanf("%lld", S5+i);
        int cnt = 0;
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)    SS1[cnt++] = S1[i] + S2[j];
        cnt = 0;
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)    SS2[cnt++] = S3[i] + S4[j];
        std::sort(SS2, SS2 + cnt);
        bool flag = false;
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < cnt; j++)
            {
                int left = 0 - S5[i] - SS2[j];
                if(binarySearch(left, cnt))
                {
                    flag = true;
                    break;
                }
            }
            if(flag)    break;
        }
        printf("%s\n", flag ? "Yes" : "No");
    }
    return 0;
}

第二种

#include <cstdio>
#include <algorithm>
#define ll long long
const int Max1 = 205, Max2 = Max1 * Max1;
ll S[5][Max1], SS1[Max2], SS2[Max2];
int N, n;


int main()
{
    scanf("%d", &N);
    while(N--)
    {
        scanf("%d", &n);
        for(int i = 0; i < 5; i++)
            for(int j = 0; j < n; j++)    scanf("%lld", &S[i][j]);
        int cnt = 0;
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < n; j++)
            {
                SS1[cnt] = S[0][i] + S[1][j];
                SS2[cnt++] = S[2][i] + S[3][j];
            }
        }
        std::sort(SS1, SS1 + cnt);
        std::sort(SS2, SS2 + cnt);
        bool flag = false;
        for(int i = 0; i < n && !flag; i++)
        {
            int j = 0, k = cnt - 1;
            ll s, x = 0 - S[4][i];       // 忘了定义为ll,WA N次
            while(j < cnt && k >= 0)
            {
                s = SS1[j] + SS2[k];
                if(s == x)
                {
                    flag = true;
                    break;
                }
                else if(s < x)    j++;
                else    k--;
            }
        }
        printf("%s\n", flag ? "Yes" : "No");
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值