OCAC暑期比赛第二场 N题 子序列 题解

子序列
【题目描述】
给定长度为n的整数序列 a[0] , a[1] , a[2] ,... a[n-1] 以及整数 S 。求出总和不小于 S 的连续子序列的长度的最小值。如果解不存在,则输出 0 。
【输入格式】
第一行包括两个整数n(1<=n<=1000000)和S(1<=S<=10^8)。
第二行有n个整数。每个整数的范围是[1,10^3]。
【输出格式】
输出总和不小于S的连续子序列的长度的最小值。
【样例输入】
10 15
5 1 3 5 10 7 4 9 2 8
【样例输出】
2
【问题分析】
这道题目可以算是一个队列的扩展题。
为了题目讲解方便起见,我们假设 a[] 数组的下标从1开始,这 n 个元素分别为 a[1],a[2],a[3],……,a[n]。
首先我们要开一个数组 sum[] , sum[i] 表示 a[1]+a[2]+...+a[i] 的和。
sum[] 数组的求解是很方便的:sum[i] = a[i] + sum[i-1] 。
那么我们求解一个区间范围 [L,R] 的元素的和就比较方便了(也就是求解a[L]+a[L+1]+……+a[R],我们接下来用 sum[L,R] 来表示这个结果),即:sum[L,R] = sum[R] - sum[L-1] (注意,这里sum[L,R]表示的是一个区间范围内的元素,sum[L]和sum[R]表示sum[]数组中的元素)
然后就是我们的重点了,我们开一个用于表示下标的变量 j ,一开始 j = 1。
我们用 ans 表示我们需要的答案,一开始给 ans 设为一个比较大的值。
然后我们从 1 到 n 循环另一个变量 i ,每次循环呢,我们判断:
只要 sum[j,i] >= S,我就更新答案为 ans = min(ans, i-j+1), j++; 直到 sum[j,i] < S 。
最后更新出来的 ans 就是我们想要的答案。
我们用队列来实现一下,实现代码如下:

#include <bits/stdc++.h>
using namespace std;
#define INF (1<<29)

int n, S, a, sum = 0, cnt = INF;
queue<int> que;

int main() {
    cin >> n >> S;
    for (int i = 0; i < n; i ++) {
        cin >> a;
        que.push(a);
        sum += a;
        while (sum >= S) {
            cnt = min(cnt, (int) que.size());
            sum -= que.front();
            que.pop();
        }
    }
    cout << (cnt == INF ? 0 : cnt) << endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ocac/p/11131701.html
今日推荐