POJ3061 Subsequence 尺取法

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


题目大意:给定长度为n的整数数列a0,a1,...,an-1以及整数S,求出总和不小于S的子串的长度的最小值。如果不存在,那么长度为0。


分析:我们设以as开始的总和最初大于等于S时的连续子序列as,as+1,...,at-1,这时as+1,...,at-2<as,...,at-2<S,所以从as+1开始的总和不小于S的连续子序列如果是as+1,...,at'-1的话,则必然有t<=t',由此我们可得如下算法:

(1)以s=t=sum=0初始化;

(2)只要依然有sum<S,就不断将sum增加at,并将t++;

(3)如果(2)中无法满足sum>=S,则终止。否则更新ans=min(ans,t-s);

(4)将sum减去as,s+1然后回到(2)。


这种反复地推进区间的开头和末尾,来求取满足条件的最小的区间的方法被称作尺取法。


实现代码如下( 复杂度为O(n) ):

#include <cstdio>
using namespace std;
const int M=1e5+10;
int a[M],n,S;
int min(int x,int y)
{
    return x<y?x:y;
}
void solve()
{
    int ans=n+1;
    int s=0,t=0,sum=0;
    while(true)
    {
        while(t<n&&sum<S)
          sum+=a[t++];
        if(sum<S) break;
        ans=min(ans,t-s);
        sum-=a[s++];
    }
    if(ans>n) ans=0; //解不存在
    printf("%d\n",ans);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&S);
        for(int i=0;i<n;i++)
          scanf("%d",&a[i]);
        solve();
    }
    return 0;
}



你可能感兴趣的:(POJ3061 Subsequence 尺取法)