HDU 2141 can you find it [二分]

1.题意:给出三组数,给出一个数X,试问是否能从三个数组中各选一个数,A,B,C使得X=A+B+C

2.分析:题设的输入数据为先是依次给出三组数的长度L、N、M,下面三行给出三组数的内容,再下面一行给出要查询的数X的个数S,最后S行是依次给出S个查询值X。其中1<=L, N, M<=500, 1<=S<=1000。首先若是朴素的考虑三个数组的任意组合,那么有L*N*M种组合,结合数据规模O(N*3)看太大了,所以将上式变形为A+B=X-C,考虑前两个数组的任何组合,有L*N种,这样对于每一个X,等式右边就有M种情况,遍历这M种情况,对于右边每一种取值,二分寻找左边L*N种取值,这样就能在O(NlogN)的规模下求解。

3.代码:Tips:数据中包含负数,且注意运算过程中有可能超过int的范围

 1 # include <iostream>
 2 # include <cstdio>
 3 # include <algorithm>
 4 using namespace std;
 5 const int MAXN=505;
 6 int COUNT=0;
 7 int L,N,M,S;
 8 long long A[MAXN],B[MAXN],C[MAXN];
 9 long AB[MAXN*MAXN],snum[2*MAXN];
10 void Init()
11 {
12     for(int i=0;i<L;i++)
13         scanf("%lld",&A[i]);
14     for(int i=0;i<N;i++)
15         scanf("%lld",&B[i]);
16     for(int i=0;i<M;i++)
17         scanf("%lld",&C[i]);
18     scanf("%d",&S);
19     int temp=0;
20     for(int i=0;i<L;i++)
21         for(int j=0;j<N;j++)
22             AB[temp++]=A[i]+B[j];
23     sort(C,C+M);
24     sort(AB,AB+L*N);
25     for(int i=0;i<S;i++)
26         scanf("%lld",&snum[i]);
27 }
28 bool judge(long long n)
29 {
30     for(int i=0;i<M;i++)
31     {
32         int l=0;
33         int r=N*L-1;
34         if((C[i]<n-AB[r])||(C[i]>n-AB[l])) continue;//不用longlong就会WA 
35         while(l<=r)
36         {
37             int mid=l+(r-l)/2;
38             if(AB[mid]+C[i]==n) return true;
39             else if(AB[mid]+C[i]>n) r=mid-1;
40             else l=mid+1; 
41         }
42     }    
43     return false;
44 }
45 void Solve()
46 {
47     printf("Case %d:\n",++COUNT);
48     for(int i=0;i<S;i++)
49     {
50         long long temp=snum[i];
51         if(judge(temp)) printf("YES\n");
52         else printf("NO\n");
53     }
54 }
55 int main()
56 {
57     while(scanf("%d%d%d",&L,&N,&M)!=EOF)
58     {
59         Init();
60         Solve();
61     }
62     return 0;
63 }

 

posted @ 2017-07-29 00:33  cn_XuYang  阅读(203)  评论(0编辑  收藏  举报