尺取详解 (Subsequence)

有这么一类问题,需要在给的一组数据中找到不大于某一个上限的“最优连续子序列”

于是就有了这样一种方法,找这个子序列的过程很像毛毛虫爬行方式比较流行的叫法是“尺取法”。

Poj3061     

给长度为n的数组和一个整数m,求总和不小于m的连续子序列的最小长度

输入

n = 10,m = 15

5 1 3 5 10 7 4 9 2 8

输出

2

那么我们先用sum存当前这个子序列的和,从左边第一个数来存,直到这个子序列的和大于等于m为止,再记录下当前长度。

其实相当于当不满足条件就入队,然后得到队列长度,再将队首元素出队,再进行下一次的入队,直到满足条件再次出队,并且将这一次的长度与历史最短长度进行取舍,最后扫到最后的元素却无法再满足入队条件的时候就结束,此时用O(n)的时间就可以得到答案。

如下,我把样例用毛毛虫爬一遍,红色的是当前“毛毛虫着地”也就是刚好满足题意的子序列的地方:

5 1 3 5 10 7 4 9 2 8

1 3 5 10 7 4 9 2 8

5 1 3 5 10 7 4 9 2 8

5 1 3 5 10 7 4 9 2 8

5 1 3 5 10 7 4 9 2 8

5 1 3 5 10 7 4 9 2 8

5 1 3 5 10 7 4 9 2 8

5 1 3 5 10 7 4 9 2 8

5 1 3 5 10 7 4 9 2 8

  以上转自   http://blog.chinaunix.net/uid-24922718-id-4848418.html

A sequence of N positive integers (10 < N < 100 000), each of them less than or equal 10000, and a positive integer S (S < 100 000 000) are given. Write a program to find the minimal length of the subsequence of consecutive elements of the sequence, the sum of which is greater than or equal to S.

Input

The first line is the number of test cases. For each test case the program has to read the numbers N and S, separated by an interval, from the first line. The numbers of the sequence are given in the second line of the test case, separated by intervals. The input will finish with the end of file.

Output

For each the case the program has to print the result on separate line of the output file.if no answer, print 0.

Sample Input

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

Sample Output

2
3

给出了n个正整数序列(10<n<100,000),它们均小于或等于10000,正整数s(s<100 000 000)。编写一个程序来查找序列的连续元素的子序列的最小长度,其总和大于或等于S。

输入

第一行是测试用例的数量。对于每个测试用例,程序必须从第一行读取由间隔分隔的数字n和s。序列的数目在测试用例的第二行中给出,由间隔分隔。输入将以文件结尾完成。

产量

对于每种情况,程序都必须在输出文件的单独行上打印结果。如果没有答案,请打印0。

思路

那么我们先用sum存当前这个子序列的和,从左边第一个数来存,直到这个子序列的和大于等于m为止,然后从这个子序列的头开始减,减到小于s为止,每当子序列改变并且sum大于s时,就记算长度于min比较,取最小。

代码:

#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        long long n,s,a[1000100];
        scanf("%lld %lld",&n,&s);
        int i,k,j;
        for(i=0;i<n;i++)
            scanf("%lld",&a[i]);
        long long st,en,sum=0;
        long long minn=1e9;
        st=0;en=0;
        for(;;)
        {
            sum+=a[en];
            while(sum>=s)
            {
                long long t=en-st+1;
                if(t<minn)
                    minn=t;
                st++;
                sum-=a[st-1];
            }
            en++;
            if(en==n)
                break;
        }
        if(minn==1e9)
            minn=0;
        printf("%lld
",minn);
    }
    return 0;
}

另一道非常好的题:https://blog.csdn.net/Septembre_/article/details/81086868

原文地址:https://www.cnblogs.com/jk17211764/p/9677403.html