1. 程式人生 > >HDU 2141 can you find it 二分

HDU 2141 can you find it 二分

cnblogs algorithm main 依次 樸素 合數 ret void style

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 }

HDU 2141 can you find it 二分