尺取法入门--poj 3061

xiaoxiao2021-02-27  169

Subsequence Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 16457 Accepted: 6982

Description

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

题的意思给出  a1,a2,a3,.....an-1  以及整数s,求总和不小于s的最短连续子序列,如果不存在输出0;

可以用区间【s,t)的总和 加二分快速搜索解决     sum[i]=a0+a1+a2+ai-1; 想要求得某一区间【s,t)的总和大于sum

可以枚举每一个数据,做一下操作:   元素(sum[i])

 求得当前元素sum【s】到sum【n】中的大于等于sum【s】+S的第一个元素的下标   t    然后用t减去s的下标  即为大于S的和的序列,  然后设一个更新最小值的语句,就可以求出最小值了

贴一下这个代码:

int n,s; int a[max] int sum[manx+1]; void solve() { for(itn i=0;i<n;i++) sum[i+1]=sum[i]+a[i]; if(sum[n]<S) {cout<<0<<endl; return ; } int res=n; for(int s=0;sum[s]+S<=sum[n];s++) { int t=lower_bound(sum+s,sum+n,sum[s]+S); //求得从s点到t点的大于等于S的t点坐标 res=min(res,t-s);//求得了最小的区间 } cout<<res<<endl; } 这个算法的复杂度为  o(logn*n)  还可以优化,那当然是这篇文章的核心了,尺取法!!!

下面放思想:

以a[s]开始的总和大于S时的连续子序列为a[s], a[s+1],  a[s+2],;....a[t-1]>=S  ,1.是不是就有a[s]----a[t-2]<S了呢,2.是不是有 a[s+1]--a[t-1]<S了呢   开始说的标准区间就是从这两种情况演变过来的,因此 可以设计出一下算法

1)以s=t=sum=0开始

2)只要依然有sum<S;就不断增加a[t]并将t++;

3)如果2)中的无法满足sum>=S则终止,满足的直接更新res

4)将sum减去a[s],s++然后回到2)  (这个是基于3)成立的情况下才执行的操作)

在这个算法中,t最多变化n次,因此只需要o(n)的复杂度

下面放代码:

void solve() { itn res=n+1; int s=0,t=0,sum=0; for(;;) { while(t<n&&sum<S)//加数加到大于等于S的操作 sum+=a[t++]; if(sum<S) break;//直接就确定了所有的元素之和都小于了S res=min(res,t-s); sum-=a[s++]; } if(res>n) res=0; cout<<res<<endl; }

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

转载请注明原文地址: https://www.6miu.com/read-16125.html

最新回复(0)