尺取法 POJ 3601 Subsequence

 

题目传送门

 1 /*  2  题意:求连续子序列的和不小于s的长度的最小值  3  尺取法:对数组保存一组下标(起点,终点),使用两端点得到答案  4  1. 记录前i项的总和,求[i, p)长度的最小值,用二分找到sum[p] - s[i] >= s的p  5  2. 除了O (nlogn)的方法,还可以在O (n)实现,[i, j)的区间求和,移动两端点,更新最小值,真的像尺取虫在爬:)  6 */  7 #include <cstdio>  8 #include <algorithm>  9 #include <cstring> 10 #include <cmath> 11 using namespace std; 12 13 typedef long long ll; 14 const int MAXN = 1e5 + 10; 15 const int INF = 0x3f3f3f3f; 16 int a[MAXN]; 17 ll sum[MAXN]; 18 19 int main(void) //POJ 3601 Subsequence 20 { 21 int t; scanf ("%d", &t); 22 while (t--) 23  { 24 memset (sum, 0, sizeof (sum)); 25 int n, s; 26 scanf ("%d%d", &n, &s); 27 for (int i=1; i<=n; ++i) {scanf ("%d", &a[i]); sum[i] = sum[i-1] + a[i];} 28 29 if (sum[n] < s) {puts ("0"); continue;} 30 31 int ans = n; 32 for (int i=1; sum[i]+s<=sum[n]; ++i) 33  { 34 int p = lower_bound (sum+i, sum+1+n, sum[i] + s) - sum; 35 ans = min (ans, p - i); 36  } 37 38 printf ("%d\n", ans); 39  } 40 41 return 0; 42 } 43 44 45 /* 46 2 47 10 15 48 5 1 3 5 10 7 4 9 2 8 49 5 11 50 1 2 3 4 5 51 */
 1 #include <cstdio>  2 #include <algorithm>  3 #include <cstring>  4 #include <cmath>  5 using namespace std;  6  7 typedef long long ll;  8 const int MAXN = 1e5 + 10;  9 const int INF = 0x3f3f3f3f; 10 int a[MAXN]; 11 12 int main(void) //POJ 3601 Subsequence 13 { 14 int t; scanf ("%d", &t); 15 while (t--) 16  { 17 int n, s; 18 scanf ("%d%d", &n, &s); 19 for (int i=1; i<=n; ++i) scanf ("%d", &a[i]); 20 21 int ans = n + 1; int i = 1, j = 1; ll sum = 0; 22 while (1) 23  { 24 while (j <= n && sum < s) sum += a[j++]; 25 if (sum < s) break; 26 ans = min (ans, j - i); 27 sum -= a[i++]; 28  } 29 30 if (ans == n + 1) puts ("0"); 31 else printf ("%d\n", ans); 32  } 33 34 return 0; 35 } 36 37 38 /* 39 2 40 10 15 41 5 1 3 5 10 7 4 9 2 8 42 5 11 43 1 2 3 4 5 44 */
O (n)

 

你可能感兴趣的:(sequence)