挑战3.2.1 Subsequence (poj 3061)

题目

尺取法

这里写图片描述

分析


给了一串数,找一个子串使得他们的和大于给定的数S。复杂的方法这里就不多说了,介绍一下尺取法。

  • 基本思想
    通过首位缩小区间的长度来求解最小的那个长度

  • 具体步骤
    给定s, t来表示首尾的一个指针。sum表示当前区间的和,res记录最短的长度。
    1.将s=t=sum初始化0
    2.只要sum < S,就将t指针向后移,并把S加上后面的一个数。(当sum>S停止)
    3.(此时的sum满足条件,但是长度不一定最小)将sum减去最前面的一个数,s向后移动一个。
    4.当sum< S时退出循环(本来在操作2的时候应该大于S的,小于S表示从s开始到最后一个数都加上还是不能满足sum大于S,就没有必要继续操作3了)

  • 代码

#include <iostream>
using namespace std;
int min(int a, int b)
{
    return a < b ? a : b;
}
int main()
{
    int test;
    cin >> test;
    while (test--)
    {
        int n, s;
        cin >> n >> s;
        int num[100005] = { 0 };
        for (int i = 0; i < n; i++)
            cin >> num[i];
        long long int res = n + 1, j = 0, i = 0;
        long long int sum = 0;
        while (1)
        {
            while (sum < s&&j < n)
                sum += num[j++];
            if (sum < s) break;
            res = min(res, j - i);
            sum -= num[i++];
        }
        if (res>n) cout<<0<<endl;
        else cout<<res<<endl;
    }
    return 0;
}

实际这题也相当于是一种dp,dp[i]表示从i开始向后加和刚好大于S的最小长度,但是当i>某个数的时候即使加到了最后一个数也不一定满足大于S这个条件。因此上面只要在执行了1以后还不能满足就可以退出这个大循环了

猜你喜欢

转载自blog.csdn.net/cugsl/article/details/78165027