HDU - 2141

超市一共有ABC三个货架, 每个货架上都有若干种商品(每种有无限多个), 比如A货架上的第i种商品的价格是Ai元.

白学姐发了K个红包, 但是ta要求对于每个红包, 从三个货架上各拿一个商品, 把红包里的钱恰好花光, 这可能吗?

Input

每个输入包含多组样例.
每组样例的第一行有三个整数L, N, M(1<=L, N, M<=500), 表示A, B, C三个货架上分别有L, N, M种商品
接下来三行, 每行分别有L, N, M个数字, 代表A, B, C三个货架上每种商品的价格.
第五行有一个整数K表示有K个红包, 1<=K<=1000
接下来K行每行有一个数代表一个红包内的钱数

所有整数均在32位整型的范围内

Output

对于第i组样例输出一行Case i:
接下来K行对于每个红包的期望输出一行 如果可以满足则输出 YES 否则输出 NO

Sample Input

3 3 3
1 2 3
1 2 3
1 2 3
3
1
4
10

Sample Output

Case 1:
NO
YES
NO

 

题意:

给三个长度分别为L,N,M数数组,从每个数组里面取出一个数相加,如果存在和为K的数,就输出YES,反之,就输出NO

题解:

话不多说,先给代码:

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
using namespace std;
int main()
{
    int a[501],b[501],c[501];
    int L,N,M;
    scanf("%d%d%d",&L,&N,&M);
    for(int i=1;i<=L;++i)
        scanf("%d",&a[i]);
    for(int i=1;i<=N;++i)
        scanf("%d",&b[i]);
    for(int i=1;i<=M;++i)
        scanf("%d",&c[i]);
    int num;
    cin>>num;
    while(num)
    {
        int number;
        int judgee=0;
        cin>>number;
        for(int i=1;i<=L;++i)
            for(int j=1;j<=N;++j)
        {
            for(int k=1;k<=M;++k)
            {
                if(a[i]+b[j]+c[k]==number)
                {
                    judgee=1;
                }
            }
        }
        if(judgee==1)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

上面的代码可以通过样例,但是时间超限,因为三层for循环,算一下就是500*500*500.

那,该怎么做呢?

可以使用二分的方法进行优化,这样时间复杂度就降下来了,那么就讨论一下怎么二分。

首先,一共有三层for循环,那么这三层for循环就可以作为我们优化的突破口

我们可以把前两层for循环相加得到的数据存入一个数组,然后遍历第三层for循环的数据,在每一次遍历的时候二分前面的那个数组。

 

 

#include<stdio.h>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<iostream>
#include<queue>
#include<string>
using namespace std;
int a[505],b[505],c[505];
int num[251000];
int main()
{
    int L,N,M,v=1;
   while(~scanf("%d%d%d",&L,&N,&M))
   {
       printf("Case %d:\n",v++);
       int cnt=0;
       for(int i=0;i<L;++i)
        scanf("%d",&a[i]);
       for(int j=0;j<N;++j)
        scanf("%d",&b[j]);
       for(int k=0;k<M;++k)
        scanf("%d",&c[k]);
       for(int i=0;i<L;++i)
       {
           for(int j=0;j<N;++j)
           {
               num[cnt++]=a[i]+b[j];
           }
       }
       sort(num,num+cnt);
       int m;
       cin>>m;
       while(m--)
       {
           int judge;
           int number;
           cin>>number;
           for(int i=0;i<M;++i)
           {
               judge=1;
               int findd=number-c[i];
               int left=1,right=cnt;
               int mid=(left+right)/2;
               while(left<right)
               {
                   if(num[mid]<findd) left=mid+1;
                   else if(num[mid]>findd) right=mid-1;
                   else
                    break;
                   mid=(left+right)/2;
               }
               if(num[mid]==findd)
               {
                   judge=0;
                   break;
               }
           }
           if(judge==0)
            printf("YES\n");
           else
            printf("NO\n");

       }
   }

   return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值