题目大意 给定一个长度为N的数列,以及整数S。求出和不小于S的连续子序列的长度的最小值。如果解不存在,则输出0.
题目分析 先求前缀和,然后就能用O(1)的时间, 求出一个区间的和。
之后用二分就能解决这道题。
但《挑战程序设计竞赛》(P146)中提供了一种更高效和简单的解法,叫“尺取法”。
source code solution 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include <iostream> using namespace std ;const int maxn = 100010 ;typedef long long ll;ll a[maxn], sum[maxn]; int N;ll S; bool judge (int len) { for (int i = 0 ; i + len <= N; i++) { if (sum[i + len] - sum[i] >= S) return true ; } return false ; } int main () { ios::sync_with_stdio(false ); cin .tie(0 ); int T; cin >> T; while (T--) { cin >> N >> S; for (int i = 0 ; i < N; i++) cin >> a[i]; sum[0 ] = 0 ; for (int i = 0 ; i < N; i++) sum[i + 1 ] = sum[i] + a[i]; if (sum[N] < S) { cout << 0 << endl ; continue ; } int L = 0 , R = N; while (L + 1 < R) { int mid = (L + R) / 2 ; if (judge(mid)) R = mid; else L = mid; } cout << R << endl ; } }
solution 2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <iostream> #include <algorithm> using namespace std ;const int maxn = 100010 ;typedef long long ll;ll a[maxn]; int N;ll S; int main () { ios::sync_with_stdio(false ); cin .tie(0 ); int T; cin >> T; while (T--) { cin >> N >> S; for (int i = 0 ; i < N; i++) cin >> a[i]; int s = 0 , t = 0 ; ll sum = 0 ; int ans = N + 1 ; for (;;) { while (t < N && sum < S) sum += a[t++]; if (sum < S) break ; ans = min(ans, t - s); sum -= a[s++]; } if (ans > N) ans = 0 ; cout << ans << endl ; } }
Last updated: 2018-05-02 14:38:14