HDU2141/POJ2785(二分查詢)
HDU - 2141 Can you find it?
Give you three sequences of numbers A, B, C, then we give you a number X. Now you need to calculate if you can find the three numbers Ai, Bj, Ck, which satisfy the formula Ai+Bj+Ck = X. Input
There are many cases. Every data case is described as followed: In the first line there are three integers L, N, M, in the second line there are L integers represent the sequence A, in the third line there are N integers represent the sequences B, in the forth line there are M integers represent the sequence C. In the fifth line there is an integer S represents there are S integers X to be calculated. 1<=L, N, M<=500, 1<=S<=1000. all the integers are 32-integers. Output
For each case, firstly you have to print the case number as the form “Case d:”, then for the S queries, you calculate if the formula can be satisfied or not. If satisfied, you print “YES”, otherwise print “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
問題求A+B+C=X是否存在
暴力求解求出三個陣列所有值的可能然後從中查詢是否有該值是不可行的,其時間複雜度為O(N^3)。
可以將等式進行變換為A+B=X-C,這樣需要在A+B所有的可能值中查詢X-C是否存在,將時間複雜度降為O(N^2),同時查詢我們使用二分查詢更快速。
#include<iostream> #include<algorithm> using namespace std; int a[501], b[501],c[501],box[250005], s; //box注意開大,避免陣列記憶體不夠 int l, n, m, k; int binary_search(int x) //在box中二分查詢x { int left = 1, right = k; while (left <= right) { int mid = (left + right) / 2; if (x > box[mid]) left = mid + 1; else if (x < box[mid]) right = mid - 1; else return 1; } return 0; } int main() { int cases = 0; while (scanf("%d%d%d", &l, &n, &m) != EOF) { cases++; for (int i = 1; i <= l; i++) cin >> a[i]; for (int i = 1; i <= l; i++) cin >> b[i]; k = 0; for (int i = 1; i <= l; i++) //計算兩組數和的所有可能並排序 { for (int j = 1; j <= n; j++) { box[++k] = a[i] + b[j]; } } sort(box + 1, box + k+1); for (int i = 1; i <= l; i++) cin >> c[i]; cin >> s; cout << "Case " << cases << ':' << endl; while (s--) { int x; cin >> x; int flag = 0; for (int i = 1; i <= m; i++) { if (binary_search(x - c[i])) { flag = 1; break; } } if (flag) cout << "YES" << endl; else cout << "NO" << endl; } } return 0; }
POJ2785 4 Values whose Sum is 0
Time Limit: 15000MS | Memory Limit: 228000K | |
Total Submissions: 29423 | Accepted: 8951 | |
Case Time Limit: 5000MS |
Description
The SUM problem can be formulated as follows: given four lists A, B, C, D of integer values, compute how many quadruplet (a, b, c, d ) ∈ A x B x C x D are such that a + b + c + d = 0 . In the following, we assume that all lists have the same size n .
Input
The first line of the input file contains the size of the lists n (this value can be as large as 4000). We then have n lines containing four integer values (with absolute value as large as 228 ) that belong respectively to A, B, C and D .
Output
For each input file, your program has to write the number quadruplets whose sum is zero.
Sample Input
6 -45 22 42 -16 -41 -27 56 30 -36 53 -37 77 -36 30 -75 -46 26 -38 -10 62 -32 -54 -6 45
Sample Output
5
Hint
Sample Explanation: Indeed, the sum of the five following quadruplets is zero: (-45, -27, 42, 30), (26, 30, -10, -46), (-32, 22, 56, -46),(-32, 30, -75, 77), (-32, -54, 56, 30).
暴力列舉明顯是不可能的,可以轉化為A+B=-(C+D),將A+B所有值放入一個數組中然後從陣列中二分查詢-(C+D)。
所求所有可能的總數,故需要計算-(C+D)在陣列中是否存在,存在則有幾個,就用到了STL中的上下界二分查詢。
#include<iostream>
#include<algorithm>
using namespace std;
int a[4001], b[4001], c[4001], d[4001], box1[16000000], box2[16000000];
int n, k1 = 0, k2 = 0, ans = 0; //box1中存放A+B,box2中存放C+D
int main()
{
while (scanf("%d", &n) != EOF)
{
k1 = 0, k2 = 0, ans = 0;
for (int i = 1; i <= n; i++)
scanf("%d%d%d%d", &a[i], &b[i], &c[i], &d[i]);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
box1[++k1] = a[i] + b[j];
sort(box1 + 1, box1 + k1 + 1); //在box1中二分查詢,從小到大排序
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
box2[++k2] = c[i] + d[j];
for (int i = 1; i <= k2; i++)
{
int x1 = lower_bound(box1 + 1, box1 + k1+1, -box2[i]) - box1;//下界的角標序號
int x2 = upper_bound(box1 + 1, box1 + k1+1, -box2[i]) - box1; //上界的角標序號
if (x1 != x2) //序號不相同則至少存在一個
ans += (x2 - x1);
}
cout << ans << endl;
}
return 0;
}