传送门
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 11284 | Accepted: 4694 |
Description
Input
Output
Sample Input
2
10 15
5 1 3 5 10 7 4 9 2 8
5 11
1 2 3 4 5
Sample Output
2
3
Source
题目大意:
给定T组数据,每组数据有一个数n,表示有n个数,然后再给定一个数S,让你求这个数列总和>=S的长度的最小值。(数据范围 n<1e5,S<1e8,a[i]<=1e4)
解题思路:
(1)首先说一下复杂度为 O(n*log(n))的算法
因为所有的元素都是>0的,所以我们可以想到的是假设数列 ai ai+1 ai+2 ....at-1 的和>=S,那么我们可以求一下这些数列的前i项和,现在定义sum[i]为a0 a1 a2 ...ai-1的,那么ai ai+1 ai+2 ... at-1 就可以写成 sum[t] - sum[i], 因为 sum[t]-sum[i] >= t,那么我们要求的是这些长度的最小值,所以就是 t-i 的最小值,那么我们可以先预处理计算sum[i]的值,然后在可以进行二分算法求 t-i 的最小值
My Code:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN = 100000+5; int a[MAXN],sum[MAXN]; int n; void get_Sum() { sum[0] = 0; for(int i=0; i<n; i++) sum[i+1] = sum[i] + a[i]; } int main() { int T,S; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&S); for(int i=0; i<n; i++) scanf("%d",&a[i]); get_Sum(); if(sum[n] < S) puts("0"); else { int ans = n + 100; for(int i=0; sum[i]+S<=sum[n]; i++) { int tmp = lower_bound(sum+i,sum+n,S+sum[i])-sum; ans = min(ans,tmp-i); } cout<<ans<<endl; } } return 0; }
现在就得说一下尺取法了,其实尺取法的关键就是两个指针都是从头开始的,两个指针s, t,if(sum<S)那么sum+=a[t],t++;否则的话,sum -= a[s],s++;抓住这个关键就行了,在不满足条件的时候不要忘记更新 ans,ans始终是s-t的最小值。。。
My Code:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN = 100000+5; int a[MAXN]; int main() { int T,S,n; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&S); for(int i=0; i<n; i++) scanf("%d",&a[i]); int t=0, s=0, sum=0; int ans = n + 100; while(1) { while(t<n && sum<S) { sum += a[t]; t++; } if(sum < S) break; ans = min(ans, t-s); sum -= a[s]; s++; } if(ans == n+100) puts("0"); else { cout<<ans<<endl; } } return 0; }