[POJ3061]Subsequence(二分,前缀和)

题目链接:http://poj.org/problem?id=3061

题意:给一个长为n的数列和整数s,求一个连续的子序列,使得这个子序列长度最短并且不小于这个整数s。

统计[1~i]的子序列和sum(i),(sum(0)=0)。然后求一个区间[i,j]的和即为sum(j)-sum(i-1) (i > 0)。

由于给定序列没有负数,因此sum是个严格不减的序列。

转换成一个求最大值最小的问题,可以二分枚举序列长度,在前缀和上计算子序列[i-1,i+m-1]的和。如果存在一个满足子序列和≥s的,则缩小序列长度并记下当前值,反之扩大。复杂度为O(nlgn)。

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <iomanip>
 4 #include <cstring>
 5 #include <climits>
 6 #include <complex>
 7 #include <fstream>
 8 #include <cassert>
 9 #include <cstdio>
10 #include <bitset>
11 #include <vector>
12 #include <deque>
13 #include <queue>
14 #include <stack>
15 #include <ctime>
16 #include <set>
17 #include <map>
18 #include <cmath>
19 
20 using namespace std;
21 
22 const int maxn = 100010;
23 int n, s;
24 int x[maxn];
25 int sum[maxn];
26 
27 bool ok(int mm) {
28     for(int i = 1; i <= n - mm + 1; i++) {
29         // printf("%d %d\n", i-1, i+mm-1);
30         if(sum[i+mm-1] - sum[i-1] >= s) return 1;
31     }
32     return 0;
33 }
34 
35 int main() {
36     // freopen("in", "r", stdin);
37     int T;
38     scanf("%d", &T);
39     while(T--) {
40         memset(sum, 0, sizeof(sum));
41         scanf("%d %d", &n, &s);
42         for(int i = 1; i <= n; i++) {
43             scanf("%d", &x[i]);
44             sum[i] = sum[i-1] + x[i];
45         }
46         if(sum[n] < s) {
47             printf("0\n");
48             continue;
49         }
50         int ans;
51         int ll = 0;
52         int rr = n;
53         while(ll <= rr) {
54             int mm = (ll + rr) >> 1;
55             if(ok(mm)) {
56                 ans = mm;
57                 rr = mm - 1;
58             }
59             else ll = mm + 1;
60         }
61         printf("%d\n", ans);
62     }
63 }

 

此题也可以用尺取法,维护两个指针从左到右扫描所存序列,复杂度为O(n)。

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <iomanip>
 4 #include <cstring>
 5 #include <climits>
 6 #include <complex>
 7 #include <fstream>
 8 #include <cassert>
 9 #include <cstdio>
10 #include <bitset>
11 #include <vector>
12 #include <deque>
13 #include <queue>
14 #include <stack>
15 #include <ctime>
16 #include <set>
17 #include <map>
18 #include <cmath>
19 
20 using namespace std;
21 
22 const int maxn = 100010;
23 int n, s;
24 int x[maxn];
25 
26 int main() {
27     // freopen("in", "r", stdin);
28     int T;
29     scanf("%d", &T);
30     while(T--) {
31         scanf("%d %d", &n, &s);
32         int sum = 0;
33         for(int i = 1; i <= n; i++) {
34             scanf("%d", &x[i]);
35             sum += x[i];
36         }
37         if(sum < s) {
38             printf("0\n");
39             continue;
40         }
41         int ans = 0x7f7f7f;
42         int ll = 1;
43         int rr = 1;
44         sum = 0;
45         while(1) {
46             while(rr <= n && sum <= s) {
47                 sum += x[rr++];
48             }
49             if(sum < s) break;
50             ans = min(ans, rr-ll);
51             sum -= x[ll++];
52         }
53         printf("%d\n", ans);
54     }
55 }

 

posted @ 2016-04-18 16:43  Kirai  阅读(207)  评论(0编辑  收藏  举报