问你一串数字中某几个连续数字和大于等于S,最少个数是多少。
利用前缀和,构造有序性,再二分查找最少长度。O(nlogn)。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define ll long long
#define INF 2139062143
#define MAXN 100005
using namespace std;
int sum[MAXN],S;
bool Judge(int a,int b,int c)
{
if(a-b>=c) return true;
return false;
}
int Bsearch(int low,int high,int now)
{
int mid=(low+high)/2;
while(low<high)
{
if(Judge(sum[mid],sum[now-1],S)) high=mid;
else low=mid+1;
mid=(low+high)/2;
}
if(Judge(sum[mid],sum[now-1],S))return mid;
else return 0;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d%d",&n,&S);
int arr[MAXN]= {0};
for(int i=1; i<=n; ++i)
scanf("%d",&arr[i]);
for(int i=1; i<=n; ++i)
sum[i]=sum[i-1]+arr[i];
int ans=INF;
for(int i=1; i<=n; ++i)
{
int x=Bsearch(i,n,i);
if(x) ans=min(ans,x-(i-1));
}
if(ans==INF) printf("0\n");
else printf("%d\n",ans);
}
return 0;
}
另一种思路,O(n),维护首尾两个指针。如果区间和小于S则尾指针加1,否则判断最小区间值,然后首指针加1
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define ll long long
#define INF 2139062143
#define MAXN 100005
using namespace std;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,S;
scanf("%d%d",&n,&S);
int arr[MAXN]= {0},sum[MAXN]= {0};
for(int i=1; i<=n; ++i)
scanf("%d",&arr[i]);
for(int i=1; i<=n; ++i)
sum[i]=sum[i-1]+arr[i];
int ans=INF,res=0;
for(int i=1,j=1; i<=n; )
{
if(sum[i]-sum[j-1]<S) ++i;
else
{
ans=min(i-(j-1),ans);
j++;
}
}
if(ans==INF) printf("0\n");
else printf("%d\n",ans);
}
return 0;
}