<题目链接>
题目大意:
给你一段长度为n的整数序列,并且给出一个整数S,问你这段序列中区间之和大于等于S的最短区间长度是多少。
解题分析:
本题可以用二分答案做,先求出前缀和,然后枚举区间长度,然后再判断其是否合法即可,复杂度$O(nlog(n))$。同时,尺取法也是一个不错的选择,通过不断的移动区间的头、尾指针来寻求答案,复杂度为 $O(n)$。
尺取法:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int n,s,val[int(1e5+5)]; int main(){ int T;scanf("%d",&T); while(T--){ scanf("%d%d",&n,&s); for(int i=1;i<=n;i++)scanf("%d",&val[i]); int sum=0,l=1,r=1; int ans=1e9; while(true){ //推进区间的头结点和尾节点 while(sum<s && r<=n)sum+=val[r++]; if(sum<s)break; ans=min(ans,r-l); sum-=val[l++]; } if(ans==1e9)puts("0"); else printf("%d ",ans); } }
二分答案:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 1e5+5; int n,s; int sum[N]; bool check(int x){ //判断是否有符合条件的区间 for(int i=1;i+x-1<=n;i++){ if(sum[i+x-1]-sum[i-1]>=s)return true; }return false; } int main(){ int T;scanf("%d",&T);while(T--){ sum[0]=0; scanf("%d%d",&n,&s); for(int i=1;i<=n;i++) scanf("%d",&sum[i]),sum[i]+=sum[i-1]; int l=0,r=n,ans=-1; while(l<=r){ //二分答案,枚举区间长度 int mid=l+r>>1; if(check(mid))ans=mid,r=mid-1; else l=mid+1; } if(ans==-1)puts("0"); else printf("%d ",ans); } }
2019-03-03