计算机 1s 的计算能力:1000 000 次, 游刃有余; 10 000 000,勉强; 100 000 000,很悬,一般不能。
1.1 抽签
有 n 张纸片, 每个纸片上一个任意数字 ki 。取出 1 张,记下数字后放回,取 4 次。如果 4 个数字的和是 m, 则赢。给定一个 m, 判断是否有赢的可能性 (输出 Yes or No)。
Limits : (1 <= n <= 1000, 1 <= m <= 108, 1<= ki <= 108)
样例1:输入:n = 3, m = 10, k = {1, 3, 5} 输出: Yes (如:1, 1, 3, 5)
样例2:输入:n = 3, m = 9, k = {1, 3, 5} 输出: No (不存在)
思路: 若递归四次: 10004 >> 109, 肯定超时,故此方法不可取。
优化方法:任意两个的和共 n2 个, 只要从 n2 个数中找到有没有两个数的和为 m 即可。同时,对这 n2 个数排序,利用二分查找求解。
时间复杂度: O(N2logN)
#include <iostream> #include <vector> #include <algorithm> using namespace std; int main () { int n, m; cin >> n >> m; vector<int> k(n); vector<int> sum(n*n); for (int i = 0; i < n; ++i) cin >> k[i]; /**********************************************************/ for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { sum[i*n+j] = k[i] + k[j]; } } sort(sum.begin(), sum.end()); bool exist = false; for(int i = 0; i < n; ++i) { if (binary_search(sum.begin(), sum.end(), m-sum[i])) { exist = true; break; } } if(exist) cout << "Yes" << endl; else cout << "No" << endl; return 0; }
1.6.1 三角形
有 n 根棍子,棍子 i 长度 ai, 选出 3 根组成周长尽可能长的三角形。输出最大周长,若无法组成三角形则输入为 0。
Limits: (3 <= n <= 100000, 1 <= ai <= 106)
样例1: 输入: n = 5, a = {2, 3, 4, 5, 10} 输出:12 (3, 4, 5)
样例2: 输入: n = 4, a = {4, 5, 10, 20} 输出: 0
思路: 假设 a <= b <= c。只要满足 a + b > c 即可组成三角形。
因此,2b > c ,对每个 A[i] (即 b) 只要在有序数组 A 中找出小于 2b 的第一个元素 c , 若其满足 c - b < a (即 A[i-1]), 则组成一个以 A[i] 为中间长度的边的周长最大的三角形, 否则若是 c - b >= a (即 A[i-1]), 则不存在以 A[i] 为中间边的三角形。 时间复杂度 : O(NlogN)
#include <iostream> #include <vector> #include <algorithm> using namespace std; int binary_find (vector<int>& A, int L, int H, int value) { if (A[H] < value) return A[H]; while (L <= H) { int mid = (L+H) >> 1; if (A[mid] >= value) H = mid-1; else if (A[mid+1] >= value) return A[mid]; else L = mid + 1; } return 0; } int main () { int n; cin >> n; vector<int> a(n); for (int i = 0; i < n; ++i) cin >> a[i]; /********************************************************/ sort(a.begin(), a.end()); int ans = 0; for (int i = n-2; i > 0; --i) { int c = binary_find(a, i+1, n-1, a[i] << 1); if ( c && c < a[i] + a[i-1]) { ans = c + a[i] + a[i-1]; break; } } cout << ans << endl; return 0; }
1.6.2 Ants (蚂蚁)
n 只蚂蚁以 1cm/s 的速度在长为 Lcm 的竿子上爬行,爬到端点掉落。竿子很细,导致蚂蚁相遇时只能反向爬回。每只蚂蚁距离竿子左端距离 xi, 但不知其朝向。计算所有蚂蚁落下竿子的最短时间和最长时间。
Limits: (1 <= L <= 106, 1 <= n <= 106, 0 <= xi <= L)
样例:输入: L = 10, n = 3, x = {2, 6, 7} 输出: min = 4 (左、 右、 右)
思路:由于蚂蚁都相同,所以两只蚂蚁相遇后交错而过和反向爬回是一样的。所以,可以看成每只蚂蚁是独立运动的。
void solve(int x[], int n, int L) { int minT = 0, maxT = 0; for (int i = 0; i < n; ++i) { minT = max(minT, min(x[i], L - x[i])); maxT = max(maxT, max(x[i], L - x[i])); } cout << minT << endl << maxT << endl; }