子序列(尺取模板题)

poj3061

学习博客:

语言:
子序列
时限: 1000MS   内存限制: 65536K
提交总数: 33893   接受: 14062

描述

给出了一个N个正整数(10 <N <100 000)的序列,每个正整数小于或等于10000,并给出了一个正整数S(S <100 000 000)。编写程序以查找该序列的连续元素的子序列的最小长度,其总和大于或等于S。

输入项

第一行是测试用例的数量。对于每个测试用例,程序必须从第一行读取数字N和S,并以一个间隔将其隔开。序列号在测试用例的第二行中给出,以间隔分隔。输入将以文件结尾结束。

输出量

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

样本输入

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

样本输出

2
3

首先,如果一个区间其和大于等于S了,那么不需要在向后推进右端点了,因为其和也肯定大于等于S但长度更长,所以,当区间和小于S时右端点向右移动,和大于等于S时,左端点向右移动以进一步找到最短的区间,如果右端点移动到区间末尾其和还不大于等于S,结束区间的枚举。

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e6+100;
int a[maxn];
int n,s;
int ans; 
void solve(){
    ans=0x3f3f3f;
    int l=1,r=1,sum=0,res=0;
    while(r<=n){
        while(sum<s&&r<=n){
            sum+=a[r];
            ++r;
            ++res;
        }        
        while(sum>=s){
            sum-=a[l];
            l++;
            --res;        
        }
        ans=min(ans,res+1); 
    }
    
}
int main(){
    int t;
    cin>>t;
    while(t--){
        cin>>n>>s;
        int sum=0;
        int flag=0; 
        for(int i=1;i<=n;i++){
            cin>>a[i];
            sum+=a[i];
        }
        if(sum<s){
            printf("0
");
        } 
        else{
            solve();
            printf("%d
",ans);
        }
    }
} 
原文地址:https://www.cnblogs.com/lipu123/p/13726836.html