解法一、二分+前缀和
#include <iostream>
#include <algorithm>
#include <cstring>
typedef long long ll;
using namespace std;
const int N = 100000+10;
ll a[N];
ll sum[N];
int main()
{
int t;
cin>>t;
while(t--){
memset(sum,0,sizeof(sum));
int ans = 0x3f3f3f3f;
int n,s;
cin>>n>>s;
for(int i=1;i<=n;i++) cin >> a[i],sum[i]=sum[i-1]+a[i];
if(sum[n]<s){
cout << 0 << '\n';
continue;
}
//设sum(i,j]=sum(j)-sum(i)
//sum(i,j]>=S 即 sum(j) >= S+sum(i)
for(int i=0;sum[i]+s<=sum[n];i++){
int t = lower_bound(sum+i,sum+1+n,sum[i]+s) - sum;
ans=min(ans,t-i);
}
cout << ans << '\n';
}
return 0;
}
解法二、尺取法
尺取法:反复推进区间的开头和末尾,求取满足条件的最小区间的方法;
思路
- 先推进区间的右端点,直到大于等于S;
- 更新答案
- 左区间向右移动,返回1
#include <iostream>
#include <algorithm>
#include <cstring>
typedef long long ll;
using namespace std;
const int N = 100000+10;
ll a[N];
ll sum[N];
int main()
{
int t;
cin>>t;
while(t--){
memset(sum,0,sizeof(sum));
int ans = 0x3f3f3f3f;
int n,s;
cin>>n>>s;
for(int i=1;i<=n;i++) cin >> a[i];
int L,R;
L=R=1;
ll sum=0;
while(1){
while(sum<s&&R<=n) sum+=a[R++];
//说明R>n了
if(sum<s) break;
//(R-1)-L+1 -> R-L
ans=min(ans,R-L);
sum-=a[L++];
}
if(ans>n)
cout << 0 << '\n';
else
cout << ans << '\n';
}
return 0;
}