子序列
【题目描述】:
给你由N个整数组成的序列(10 < N < 100 000),每个元素大于等于0,且小于等于10000,再给你一个S(S < 100 000 000)。编写一个程序,找到连续的元素之和不小于S的子序列中长度最小的,并输出这个长度。
【输入描述】:
第一行一个整数表示测试组数。每组测试描述如下:
第一行,两个整数N和S
第二行,N个整数,表示序列元素
【输出描述】:
对于每组测试输出一行,一个正整数表示子序列最短长度。如果无解输出0。
【样例输入】
2
10 15
5 1 3 5 10 7 4 9 2 8
5 11
1 2 3 4 5
【样例输出】
2
3
【数据范围及描述】:
时间:1s 空间:64M
这是本蒟蒻第一次写博客,尴尬到写了好几次,手抖一不注意居然清空,无语。。。
这里是求了满足条件的连续子序列最短长度。
可以这样思考:从头开始扫描,直到找到满足条件的序列。然后去掉序列的头,从序列尾继续往后走,
直到再找到一个满足条件的序列,比较长度大小。反复如此,找到最小值。(像队列一样)
设f[i]为从第一个数到第i个数的和,则f[j]-f[i]为第i+1个数到第j个数的和,j-i为该序列长度。
所以就很简单了。
head为头,tail为尾,开始往后推进扫描。如果f[tail]-f[head]<s,说明和不够,则tail++,
如果f[tail]-f[head]>=s,说明满足条件,则比较tail-head和当前最小值的长度大小。
注意最后如果全加起来都不满足,要输出0
所以题目是比较好理解的,代码也很简单,来看一下我比较菜的代码 -。-
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
int a[100005],f[100005];
int t,n,s;
int min(int a,int b)
{return (a<b?a:b);}
int main(){
//freopen("test1.in","r",stdin);
//freopen("test1.out","w",stdout);
int head,tail,ans;
cin>>t;
while(t--)
{ head=1;
tail=1;
ans=2147483647;
cin>>n>>s;
for(int i=1;i<=n;i++)
{scanf("%d",&a[i]);
f[i]=f[i-1]+a[i];}
while(tail<=n)
{ while(f[tail]-f[head]<s&&tail<=n)
tail++;
if(f[tail]-f[head]>=s)
{ans=min(ans,tail-head);
head++;}
}
if(ans==2147483647)
cout<<"0"<<endl;
else
cout<<ans<<endl;
}
return 0;
}