poj 3061(二分 or 尺取法)
https://www.cnblogs.com/violet-acmer/p/9793209.html
马上就要去上课了,先献上二分AC代码,其余的有空再补
题意:
给定长度为 n 的整数数列 a[0,1,2,........,n]以及整数 S。
求出总和不小于 S 的连续子序列的长度的最小值。
如果解不存在,则输出 0。
题解:
1、二分
由于所有的元素都大于 0 ,所以数组a[ ] 的前缀和sum[ ]为递增的序列,满足二分的条件。
首先确定子序列的起点为start(start的可能取值为 1,2,......,n)。
假设区间[start,end]是以start为子序列起点的最小区间,则需要满足 sum[end]-sum[start-1] >= S,而确定满足条件的最小的 end 用二分即可在O(longn)的时间完成。
所以总的时间复杂度为 O(nlogn)
2、尺取法
相关说明:
设以a[start]为子序列起点的总和最初大于S的连续子序列为a[start,......,end],此时 res = end-start+1;
(1):end++,找到最大的 k ,使得在去除当前子序列的前 k 个数后依旧满足 sum[end]-sum[start-1 + k] >= S,并判断是否需要更新 res。
(2):重复(2)过程,直到 end > n 为止。
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define mem(a,b) (memset(a,b,sizeof(a))) 6 const int maxn=1e5+50; 7 8 int N,S; 9 int a[maxn]; 10 int sum[maxn]; 11 int binarySearch(int val) 12 { 13 int l=0,r=N+1; 14 while(r-l > 1) 15 { 16 int mid=l+((r-l)>>1); 17 if(sum[mid] >= val) 18 r=mid; 19 else 20 l=mid; 21 } 22 return r; 23 } 24 int main() 25 { 26 int T; 27 scanf("%d",&T); 28 while(T--) 29 { 30 mem(sum,0); 31 scanf("%d%d",&N,&S); 32 int res=0; 33 for(int i=1;i <= N;++i) 34 { 35 scanf("%d",a+i); 36 sum[i] += sum[i-1]+a[i]; 37 } 38 for(int s=1;s <= N;++s) 39 { 40 int t=binarySearch(sum[s-1]+S); 41 if(t != N+1) 42 res=(res==0 || (t-s+1)<res ? t-s+1:res); 43 } 44 printf("%d\n",res); 45 } 46 }
1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 using namespace std; 5 #define pb push 6 const int maxn=1e5+50; 7 8 int N,S; 9 int a[maxn]; 10 queue<int >myqueue; 11 12 int main() 13 { 14 int T; 15 scanf("%d",&T); 16 while(T--) 17 { 18 while(!myqueue.empty()) 19 myqueue.pop(); 20 scanf("%d%d",&N,&S); 21 for(int i=1;i <= N;++i) 22 scanf("%d",a+i); 23 int end=1; 24 int sum=0; 25 int res=0; 26 while(sum < S && end <= N)//先找到以1为序列起点的满足条件的最小的end 27 { 28 sum += a[end]; 29 res++; 30 myqueue.pb(a[end++]); 31 } 32 if(sum >= S) 33 { 34 while(sum-myqueue.front() >= S)//找到满足条件的当前最小的范围 35 { 36 sum -= myqueue.front(); 37 myqueue.pop(); 38 res--; 39 } 40 while(end <= N) 41 { 42 myqueue.pb(a[end]); 43 sum += a[end++]; 44 while(sum-myqueue.front() >= S)//步骤(2) 45 { 46 sum -= myqueue.front(); 47 myqueue.pop(); 48 } 49 res= res > myqueue.size() ? myqueue.size():res;//判断是否更新 res 50 } 51 } 52 else 53 res=0; 54 printf("%d\n",res); 55 } 56 }
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 const int maxn=1e5+50; 6 7 int N,S; 8 int a[maxn]; 9 10 int Solve() 11 { 12 int start=1,end=1; 13 int res=0; 14 int sum=0; 15 while(1) 16 { 17 while(end <= N && sum < S) 18 sum += a[end++]; 19 if(sum < S) 20 break; 21 res=(res == 0 || (end-start) < res ? end-start:res); 22 sum -= a[start++]; 23 } 24 return res; 25 } 26 27 int main() 28 { 29 int T; 30 scanf("%d",&T); 31 while(T--) 32 { 33 scanf("%d%d",&N,&S); 34 for(int i=1;i <= N;++i) 35 scanf("%d",a+i); 36 printf("%d\n",Solve()); 37 } 38 }