Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 9729 | Accepted: 3914 |
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
尺取法-->挑战详解
我们设以a[s] 开始总和最初大于S时的连续子序列为a[s] + ... + a[t-1],这时a[s+1] + ... + a[t-2] < a[s] + ... + a[t-2] < S,所以从a[s+1]开始总和最初超过S的连续子序列如果是a[s+1] + ... + a[t'-1]的话,则必然有t <= t'。
算法思路:
(1)初始化s = t = sum = 0.
(2)只要依然有sum < S,就不断将sum增加a[t],并将t增加一。
(3)如果(2)中无法满足sum >= S则终止。否则 更新结果ans = min(ans, t-s)。
(4)将sum减去a[t],s增加1然后回到(2)。
代码实现:时间复杂度(n)
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int a[100000+10]; int n, S; void solve() { int t, sum, s;//s代表起始位置 int ans = n + 1;//最后结果 t = sum = s = 0; for(;;) { while(t < n && sum < S)//知道sum >= S 或者 t >= n为止 { sum += a[t++];//t为序列末位置 } if(sum < S) break;//s为起始位置的情况下找不到连续的数之和大于或者等于S ans = min(ans, t-s); sum -= a[s++];//去掉a[s],起始位置s往后走 } if(ans > n) ans = 0; printf("%d\n", ans); } int main() { int t; scanf("%d", &t); while(t--) { scanf("%d%d", &n, &S); for(int i = 0; i < n; i++) scanf("%d", &a[i]); solve(); } return 0; }
STL lower_bound: 时间复杂度(nlog(n)) 请先会用lower_bound
#include <cstdio> #include <cstring> #include <algorithm> #define MAX 100000+10 using namespace std; int sum[MAX]; int main() { int t, n, S, i, j; int Min;//最小长度 int first, pos;//序列初位置 末位置 int a; scanf("%d", &t); while(t--) { scanf("%d%d", &n, &S); sum[0] = 0; for(i = 1; i <= n; i++) { scanf("%d", &a); sum[i] = sum[i-1] + a; } if(sum[n] < S) { printf("0\n"); continue; } Min = n+1; for(first = 0; sum[first] + S <= sum[n]; first++) { //upper_bound pos = lower_bound(sum+first, sum+n, sum[first]+S) - sum; Min = min(Min, pos-first); } printf("%d\n", Min); } return 0; }