题目
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
分析与解答
题意:给出长度为n的数列以及整数s,求出总和不小于s的连续子序列长度的最小值,如果不存在,输出0
方法一:尺取法
尺取法原理;
假设a1+a2+…+a4>s
此时说明a2+a3< a1+a2+a3< s
那么如果我们想继续向前找,a2+a3+…+at>s。t一定是大于等于4
这说明,如果依次寻找,不用考虑中间点的影响,决定子序列是否满足条件的是他的两个端点,因此我们可以通过对两个端点的调控,达到遍历找出答案的目的
1.表示方法:
我们用数组存数据,sum存子序列和,然后用i表示左端点,t表示右端点
2.调控方法:
右端点向右移动,那就是t++,移动之后,sum+a[t]
左端点向右移动,就是i++,移动之后,sum-a[i]
3.移动条件:
sum< s,右端点移动,左端点不动
sum>s,左端点移动,右端点不动
4.模拟过程:
void solve(){int res=n+1;int i=0,t=0,sum=0;for(;;){while(t<n&&sum<s){sum+=a[t++];}if(sum<s) break;res=min(res,t-i);sum-=a[i++];}if(res>n){res=0;}printf("%d\n",res);
}
ac代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include<cstdio>
using namespace std;
const int mm=100010;
int a[mm];
int n,s;void solve(){int res=n+1;int i=0,t=0,sum=0;for(;;){while(t<n&&sum<s){sum+=a[t++];}if(sum<s) break;res=min(res,t-i);sum-=a[i++];}if(res>n){res=0;}printf("%d\n",res);
}int main(){int t;cin>>t;while(t--){memset(a,0,sizeof(a));cin>>n>>s;for(int i=0;i<n;++i){cin>>a[i];}solve();}
}
二分搜索法
我们想想,既然是连续子序列,那么可以通过前缀数组表示出所以子序列可能情况,我们只需找出满足条件的情况,进行判断然后输出就可以了
对于这一题,如果在i到n中有一个t,使得sum[t]-sum[i]>=s,那t-s就是他们之间的元素个数,所以我们只需找t,利用lower_bound,
我第一次用的是这个方法,用画图的方法,要搞清楚他的区间
sum[i]是从1开始存的,有人问那个循环为啥是从零开始,
因为循环从零开始是找有没有sum[i]直接就等于s了
循环从1开始的话,就正式找sum[t]了
#include <iostream>
#include <algorithm>
#include <cstring>
#include<cstdio>
using namespace std;
const int mm=100010;
int a[mm];
int sum[mm];
int n,s;void solve(){for(int i=0;i<n;++i){sum[i+1]=sum[i]+a[i];}if(sum[n]<s){printf("0\n");return ;}int res = n;for(int i=0;sum[i]+s<sum[n];++i){int t=lower_bound(sum+i,sum+n,s+sum[i])-sum;res=min(res,t-i);}printf("%d\n",res);
}int main(){int t;cin>>t;while(t--){memset(a,0,sizeof(a));memset(sum,0,sizeof(sum));cin>>n>>s;for(int i=0;i<n;++i){cin>>a[i];}//sum[0]=0;solve();}
}