poj 3061 Subsequence(二分/双指针)

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

题意

在 n 个元素的数组中寻找和不小于 s 的最短连续区间。

思路

思路一

作前缀和二分查找,时间复杂度 $O_{(nlogn)}$ 。

代码一

#include <cstdio>
#include <algorithm>
using namespace std;

const int M = 1e5 + 100;
int a[M], sum[M];

void solve() {
    int n, s; scanf("%d%d", &n, &s);
    for (int i = 0; i < n; i++) scanf("%d", &a[i]);
    for (int i = 0; i < n; i++) sum[i + 1] = sum[i] + a[i];
    if (sum[n] < s) {
        puts("0");
        return;
    }
    int res = n;
    for (int i = 0; sum[i] + s <= sum[n]; i++) {
        int j = lower_bound(sum + i, sum + n, sum[i] + s) - sum;
        res = min(res, j - i);
    }
    printf("%d\n", res);
}

int main() {
    int t; scanf("%d", &t);
    while (t--) solve();
}

思路二

双指针,在保证指针区间的和不小于 s 的同时每次删减最左端的元素,时间复杂度 $O_{(n)}$ 。

代码二

#include <cstdio>
#include <algorithm>
using namespace std;

const int M = 1e5 + 100;
int a[M], sum[M];

void solve() {
    int n, s; scanf("%d%d", &n, &s);
    for (int i = 0; i < n; i++) scanf("%d", &a[i]);
    int res = n + 1;
    for (int l = 0, r = 0, sum = 0;;) {
        while (r < n and sum < s) {
            sum += a[r++];
        }
        if (sum < s) break;
        res = min(res, r - l);
        sum -= a[l++];
    }
    if (res > n) {
        puts("0");
        return;
    }
    printf("%d\n", res);
}

int main() {
    int t; scanf("%d", &t);
    while (t--) solve();
}

 

posted @ 2020-04-21 21:14  Kanoon  阅读(195)  评论(0编辑  收藏  举报