首页 > 代码库 > poj3061 Subsequence

poj3061 Subsequence

Subsequence

 POJ - 3061 
题目大意:
给定长度为n的整数数列,以及整数S。求出总和不小于S的连续子序列的长度的最小值。若解不存在,则输出0.

Sample Input

210 155 1 3 5 10 7 4 9 2 85 111 2 3 4 5

Sample Output

23
技术分享
/*    求出前缀和,然后枚举区间起点     区间起点固定下来了之后,终点位置二分查找     不要忘了输出0的情况 */#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>using namespace std;#define maxn 100010int t,n,a[maxn],sum[maxn],s;int main(){    //freopen("Cola.txt","r",stdin);    scanf("%d",&t);    while(t--){        memset(a,0,sizeof(a));        memset(sum,0,sizeof(sum));        scanf("%d%d",&n,&s);        for(int i=1;i<=n;i++){            scanf("%d",&a[i]);            sum[i]=sum[i-1]+a[i];        }        if(sum[n]<s){printf("0\n");continue;}        int ans=n;        for(int i=1;i<=n;i++){//枚举起点             int l=i,r=n;//二分中点             while(l<=r){                int mid=(l+r)>>1;                int now=sum[mid]-sum[i-1];                if(now>=s)r=mid-1,ans=min(ans,mid-i+1);                else l=mid+1;            }        }        printf("%d\n",ans);    }}
O(nlogn)前缀和+二分查找
技术分享
/*    尺取法:    1.初始化s,t,sum    2.只要依然有sum<m,就不断将sum加a[t],并将t加1    3.如果(2)中无法满足sum>=m则终止。否则更新ans    4.将sum减去a[s],s加1然后回到2     像区间右移 */#include<iostream>#include<cstdio>#include<cstring>using namespace std;#define maxn 100010int T,n,t,a[maxn],s,m,sum;int main(){    scanf("%d",&T);    while(T--){        s=1;t=0;        sum=0;        bool flag=0;        scanf("%d%d",&n,&m);        int ans=n;        for(int i=1;i<=n;i++)scanf("%d",&a[i]);        while(1){            while(t<n&&sum<m)                sum+=a[++t];            if(sum<m)break;            ans=min(ans,t-s+1);flag=1;            sum-=a[s];s++;        }        if(flag==0){printf("0\n");continue;}        else printf("%d\n",ans);    }    return 0;} 
O(n)尺取法

poj3061 Subsequence