poj 3061 Subsequence 二分 前缀和 双指针

地址 http://poj.org/problem?id=3061

 

解法1 

使用双指针

由于序列是连续正数 

使用l r 表示选择的子序列的起始

每当和小于要求的时候 我们向右侧扩展 增大序列和

每当和大于等于要求的时候 我们将子序列左边的数字剔除 看能是在减少长度情况下 还能保持子序列和满足要求

这样在指定起点下的满足要求的最短子序列和都会被记录 然后在比较出最短长度的子序列

如图

 

 

代码

 1 #include <iostream>
 2 #include <vector>
 3 #include <algorithm>
 4 #include <memory.h>
 5 #include <queue>
 6 
 7 
 8 using namespace std;
 9 
10 
11 /*
12 Sample Input
13 6
14 10 15
15 5 1 3 5 10 7 4 9 2 8
16 5 11
17 1 2 3 4 5
18 1 2
19 1
20 1 1
21 5
22 3 9999
23 1 2 3 
24 3 0
25 1 2 3 
26 
27 Sample Output
28 2
29 3
30 */
31 const int MAX_N = 1000010;
32 int n, m;
33 int nums[MAX_N];
34 
35 int ret = MAX_N;
36 
37 void solve()
38 {
39     int sum = 0;
40     int minlen = MAX_N;
41 
42     int r = -1; int l = 0;
43 
44     while (1) {
45         if (sum < m) {
46             r++;
47             if (r >= n) break;
48             sum += nums[r];
49         }
50         else {
51             //sum >= m
52             minlen = min(minlen, r - l + 1);
53             sum -= nums[l];
54             l++;
55             if (l >= n) break;
56             if (l > r) {
57                 r = l;
58                 sum = nums[l];
59             }
60         }
61     }
62 
63 
64     if (minlen == MAX_N) minlen = 0;
65     cout << minlen << endl;
66 }
67 
68 
69 int main()
70 {
71     int loop;
72     cin >> loop;
73     while (loop--) {
74         cin >> n >> m;
75 
76         for (int i = 0; i < n; i++) {
77             cin >> nums[i];
78         }
79         ret = MAX_N;
80         solve();
81     }
82 
83     return 0;
84 }
子序列

 

//=========================================================================================

解法2 二分查找前缀和  todo

使用前缀和就可以快速定位各个子序列的和

然后使用二分查找进行查找以指定索引开始的子序列满足和要求的最短长度

最后得到所有满足需求中最短的子序列长度

代码如下

 1 #include <iostream>
 2 #include <algorithm>
 3 
 4 using namespace std;
 5 
 6 const int MAX_N = 1000010;
 7 int n, m;
 8 int nums[MAX_N];
 9 int preSum[MAX_N];
10 
11 
12 int binartSearch(int sum[],int l, int r)
13 {
14     int start = l;
15     while (l < r) {
16         int mid = (l + r) >> 1;
17         if (sum[mid] - sum[start] >= m) {
18             r = mid;
19         }
20         else {
21             l = mid + 1;
22         }
23     }
24 
25     return (l-start);
26 }
27 
28 int solve()
29 {
30     int     ret = MAX_N;
31     for (int i = 1; i <= n; i++) {
32         preSum[i] = preSum[i - 1] + nums[i];
33     }
34     //全部加起来都无法达到标准
35     if (preSum[n] < m) return 0;
36 
37     for (int i = 1; i < n; i++) {
38         //if(preSum[i]+m <= preSum[n]){
39         if (preSum[n] - preSum[i] >= m) {
40             int idx = binartSearch(preSum,i,n);
41             ret = min(ret, idx);
42         }
43     }
44 
45     if (ret == MAX_N) ret = 0;
46     return ret;
47 }
48 
49 
50 int main()
51 {
52     int loop;
53     cin >> loop;
54 
55     while (loop--) {
56         cin >> n >> m;
57         memset(nums,0,sizeof(nums));
58         memset(preSum, 0, sizeof(preSum));
59 
60         for (int i = 1; i <= n; i++) {
61             cin >> nums[i];
62         }
63         cout << solve() << endl;
64     }
65 
66     return 0;
67 }
View Code

 

posted on 2019-12-18 14:37  itdef  阅读(261)  评论(0编辑  收藏  举报

导航