【UVA1121】Subsequence

题面

  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.

题意

  给你一个序列 W Wi0),求出 rl+1 最小的满足 ri=lWiS 的子序列

解法

尺取法:
  尺取法是一种很使用的技巧,在 ACM 赛事中经常用到,这里推荐一篇博客,里面有很多例题的讲解,包括本题:http://blog.csdn.net/consciousman/article/details/52348439
  我们考虑对于 lr 区间,如果 ri=lWi 已经满足条件了,那么对于 rR ,显然有 Ri=lWiS ,所以我们实现预处理好序列的前缀和 sum[] ,然后对于一个起点 l ,二分找到最小的满足sumxsuml1S x ,答案就是最小的xl+1,复杂度O( nlogn
  我们可以发现,符合条件的区间的左端点一定是单调递增的,所以,当区间和小于S时右端点向右移动,和大于等于S时,左端点向右移动以进一步找到最短的区间,如果右端点移动到区间末尾其和还不大于等于S,结束区间的枚举,复杂度O( n

复杂度

O(nlogn)或O( n

代码

O(nlogn):

#include<iostream>
#include<cstdlib>
#include<cstdio>
#define Lint long long int
using namespace std;
const int MAXN=100010;
int w[MAXN];
int n,S;
int ans;
int get(int L)
{
    int l=L,r=n;
    while( l<=r )
    {
        int mid=(l+r)/2;
        if( w[mid]-w[L-1]>S )   r=mid-1;
        else
            if( w[mid]-w[L-1]<S )   l=mid+1;
            else   { l=mid;break ; }
    }
    if( l>n )   return n+1;
    else   return l-L+1;
}
int main()
{
    while( scanf("%d%d",&n,&S)!=EOF )
    {
        ans=n+1;
        for(int i=1,x;i<=n;i++)   scanf("%d",&x),w[i]=w[i-1]+x;
        for(int i=1;i<=n;i++)   ans=min( ans,get( i ) );
        printf("%d\n",ans==n+1 ? 0 : ans );
    }
    return 0;
}

O( n <script type="math/tex" id="MathJax-Element-20">n</script>):

#include <cstdio>
#include <algorithm>
#include <cstring>
#define MAX 100005
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
LL a[100010];
int n, t, ans = INF;
LL sum, s;
int main()
{
    scanf("%d", &t);
    while (t--){
        scanf("%d %I64d", &n, &s);
        for (int i = 0; i < n; i++) scanf("%I64d", a+i);
        int st = 0, en = 0;
        ans = INF; sum = 0;
        while (1){
            while (en<n && sum<s) sum += a[en++];
            if (sum < s) break;
            ans = min(ans, en-st);
            sum -= a[st++];
        }
        if (ans == INF) ans = 0;
        printf("%d\n", ans);
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值