POJ 3061 Subsequence [尺取法] 《挑战程序设计竞赛》3.2

来源:互联网 发布:进入国外网站软件 编辑:程序博客网 时间:2024/05/16 14:43

POJ 3061 Subsequence

题目大意:

给定长度为n的数列整数 a0,a2,...,an1 以及整数S 。求出总和不小于S的连续子序列的长度的最小值。如果解不存在,则输出0。

限制条件:
10<n<105
0<ai104
S<108

输入

第一行, T, 表示测试数据组数。
接下来T组测试数据,每组2行。
每组测试数据第一行为N和S,第二行为N个数,即a0,...an1

输出

对于每组测试数据,输出最短的满足条件的序列长度, 无法满足则输出0

样例输入

2
10 15
5 1 3 5 10 7 4 9 2 8
5 11
1 2 3 4 5

样例输出

2
3

题解:

看到题目第一时间想到刚学的二分法,从1到N 二分查找最小的满足条件的序列长度。
每次判断是否满足,时间复杂度为O(n) ,所以该算法的复杂度为 O(nlog(n))

代码:

#include <iostream>#define MAXN 100010using namespace std;int a[MAXN], N, S;bool is_ok(int m) {    int sum = 0;    bool flag = false;    for (int i = 0; i < m; i++)        sum += a[i];    if (sum >= S) return true;    if (!flag) {        for (int i = m; i < N; i++) {            sum -= a[i-m];            sum += a[i];            if (sum >= S) {                flag = true;                break;            }        }    }    return flag;}int solve() {    int l = 1, r = N;    int sum = 0;    for (int i = 0; i < N; i++)        sum += a[i];    if (sum < S) return 0;    while (l < r) {        int mid = (l+r)/2;        if (is_ok(mid)) r = mid;        else l = mid+1;    }    return r;}int main() {    int T;    ios::sync_with_stdio(false);    cin >> T;    for (int t = 0; t < T; t++) {        cin >> N >> S;        for (int i = 0; i < N; i++)            cin >> a[i];        cout << solve() << endl;    }    return 0;}




然而,这题还有时间复杂度更低的算法,正是《挑战程序设计竞赛》3.2小节介绍的 “尺取法”:

as 开始总和最初大于S时的连续子序列为as+...+at1 ,这时
as+1+...+at2<as+...+at2
所以从as+1 开始总和最初超过S的连续子序列如果是as+1+...+at1 的话,则必然有 tt 。利用这一性质便可以设计出如下算法:
(1) 以 s=t=sum=0 初始化。
(2) 只要依然有 sum<S ,就不断将sum 增加 at ,并将 t 增加1。
(3) 如果(2) 中无法满足 sumS 则终止。否则的话,更新 res=min(res,ts)
(4) 将 sum 减去 ass 增加1然后返回(2)
对于这个算法, 因为t 最多变化n 次, 因此值需O(n) 的复杂度就可以求解这个问题了。

代码:

#include <iostream>#define MAXN 100010using namespace std;int a[MAXN], N, S;int solve() {    int res = N + 1;    int s = 0, t = 0, sum = 0;    for (;;) {        while (t < N && sum < S) {            sum += a[t++];        }        if (sum < S) break;        res = min(res, t - s);        sum -= a[s++];    }    if (res > N)        res = 0;    return res;}int main() {    int T;    ios::sync_with_stdio(false);    cin >> T;    for (int t = 0; t < T; t++) {        cin >> N >> S;        for (int i = 0; i < N; i++)            cin >> a[i];        cout << solve() << endl;    }    return 0;}
0 0
原创粉丝点击