法1:前缀和+二分思想。预处理前缀和以便于求区间和,然后枚举所有区间左端,
二分查找右端,用
S
T
L
STL
STL自带的
l
o
w
e
r
_
b
o
u
n
d
lower\_bound
lower_bound即可。
时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
法2:尺取法,枚举区间左端点,根据区间单调性,让区间右端点不断增加并更新答案。
时间复杂度:
O
(
n
)
O(n)
O(n)
法1代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1e5+5;
#define mst(a) memset(a,0,sizeof a)
int pre[N];
int main(){
int t,n,s;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&s);
for(int i=1;i<=n;i++) scanf("%d",&pre[i]),pre[i]+=pre[i-1];
if(pre[n]<s){
puts("0");
continue;
}
int ans=n;
for(int i=1;i<=n;i++){
int j=lower_bound(pre+i,pre+n+1,pre[i-1]+s)-pre;//不存在则会返回n+1
if(j!=n+1&&j-i+1<ans) ans=j-i+1;
}
printf("%d\n",ans);
}
return 0;
}
法2代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1e5+5;
#define mst(a) memset(a,0,sizeof a)
int a[N];
int main(){
int t,n,s;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&s);
int tot=0;
for(int i=1;i<=n;i++) scanf("%d",&a[i]),tot+=a[i];
if(tot<s){
puts("0");
continue;
}
int ans=n;
for(int l=1,r=1,sum=a[1];r<=n;){
while(sum<s&&r<n) sum+=a[++r];
if(sum<s) break;//若此时sum仍然小于s,显然l再增加也不可能成立.
if(ans>r-l+1) ans=r-l+1;
sum-=a[l++];//更新区间左端点.
}
printf("%d\n",ans);
}
return 0;
}