avatar
fireworks99
keep hungry keep foolish

POJ 3061 Subsequence

Description

n个非负整数,给出S,求一个连续子序列,其和>= S,并使其长度最小

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

Idea(二分搜索)

连续子序列、和 -> 暗示前缀和

因为没有负数,前缀和sum[]是单调递增的

单调递增这一特点对应 ①尺取法、②lower_bound查找

Code(二分搜索)

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

int a[100005];
int sum[100005];///涉及 连续子序列的和 -> 前缀和
///因为没有负数,前缀和sum[]是单调递增的
///单调递增这一特点对应 ①尺取法、②lower_bound查找

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        int n, tot;
        cin >> n >> tot;
        cin >> a[0];
        sum[0] = a[0];
        for(int i = 1; i < n; ++i)
        {
            scanf("%d", &a[i]);
            sum[i] = sum[i - 1] + a[i];
        }
        if(sum[n - 1] < tot)
        {
            cout << '0' << '\n';
            continue;
        }
        int ans = n;
        for(int i = 0; sum[n - 1] - sum[i] >= tot; ++i)
        {    /// (sum + i) 为起点 (sum + pos) 为终点
            int pos = lower_bound(sum + i, sum + n, sum[i] + tot) - sum;
            ans = min(ans, pos - i);
        }
        cout << ans << '\n';
    }
return 0;
}

Code(尺取法)

#include <cstdio>
#include <iostream>
using namespace std;
const int INF = 0x3f3f3f3f;

int a[100005];

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        int n, tot;
        cin >> n >> tot;
        for(int i = 0; i < n; ++i)
            scanf("%d", &a[i]);
        int res = INF, l = 0, r = 0, sum = 0;
        while(1)
        {
            while(r < n && sum < tot)
                sum += a[r++];
            if(sum < tot)
                break;
            else
            {
                res = min(res, r - l);
                sum -= a[l];
                l++;
            }
        }
        if(res == INF)
            cout << '0' << '\n';
        else
            cout << res << '\n';
    }
    return 0;
}
Site by Baole Zhao | Powered by Hexo | theme PreciousJoy