Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 11168 | Accepted: 4636 |
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
题意:
给定长度为n的数列整数a0,a1,...an-1以及整数S。求出总和不小于S的连续子序列的长度的最小值。如果解不存在,则输出0.
解法一:
使用二分搜索法(STL中的lower_bound函数)
使用方法见:http://blog.csdn.net/a2459956664/article/details/51121180
#include <cstdio> #include <algorithm> using namespace std; const int maxn = 100000 + 10; int n, S; int a[maxn]; int sum[maxn]; void solve() { //计算sum for (int i = 0; i < n; i++) sum[i + 1] = sum[i] + a[i]; if (sum[n] < S){ //解不存在 printf("0\n"); return; } int res = n; for (int s = 0; sum[s] + S <= sum[n]; s++){ //利用二分搜索求出t int t = lower_bound(sum + s, sum + n, sum[s] + S) - sum; res = min(res, t - s); } printf("%d\n", res); } 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; }
我们设以as开始总和大于S时的连续子序列为as + ... + at-1,这时as+1+...+at-2<as+...+at-2<S
所以从as+1开始总和最初超过S的连续子序列如果是as+1+...+at'-1的话,则必然有t<=t'。利用这一性质便可以设计出如下算法:
(1)以s = t = sum = 0初始化
(2)只要依然有sum < S,就不断将sum增加at,并将t增加1
(3)如果(2)中仍无法满足sum >= S则终止。否则的话,更新res = min(res, t - s)。
(4)将sum减去as,s增加1然后回到(2)。
#include <cstdio> #include <algorithm> using namespace std; const int maxn = 100000 + 10; int n, S; int a[maxn]; void solve() { int res = n + 1; int s = 0, t = 0, sum = 0; for ( ; ; ){ while (t < n && sum < S){ sum += a[t++]; } if (sum < S) break; res = min(res, t - s); sum -= a[s++]; } if (res > n){ //解不存在 res = 0; } printf("%d\n", res); } 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; }