Subsequence POJ - 3061 (二分 尺取)

在这里插入图片描述

题意: 给出n个整数a[i], 求总和不小于S的连续子序列的最小长度, 不存在输出0

题解: 这道题可用二分, 也可用尺取来做(尺取的经典题目), 首先简单说一下二分
这道题用二分法写的话也有一个比较巧妙的地方, 就是预处理:

  • 定义sum[i]表示 0 i a i \sum_0^iai
  • 序列a[i-j]和即为sum[j]-sum[i]
  • 判定条件check函数意为: 以t结尾时不小于S的序列长度是否小于当前最优长度

就不实现了, 白书上都有, 复杂度为nlogn

下面来说一下尺取法.
尺取法, 顾名思义就是像尺子一样, 一格一格的来取, 这道题大致分为以下几步

  • i, j作为尺取当前区间的下标, sum表示当前区间和
  • j 向后遍历直至sum >= S
  • 如果遍历至n, sum依然<S则结束遍历
  • 比较并取最优解
  • i 向后移动一位
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
using namespace std;
#define ms(x, n) memset(x,n,sizeof(x));
typedef  long long LL;
const LL maxn = 1e5+10;

int T, n, S, a[maxn];
int main()
{
    cin >> T;
    while(T--){
        cin >> n >> S;
        for(int i = 1; i <= n; i++)
            cin >> a[i];

        int i = 1, j = 1, sum = 0, ans = 1<<30;
        while(1){
            while(j<=n && sum<S)
                sum += a[j++]; //找到不大于S的序列
            if(sum < S) break; //终止条件
            ans = min(ans, j-i);
            sum -= a[i++]; //向前移动一格
        }
        if(ans < (1<<30)) cout << ans << endl;
        else cout << "0" << endl;
    }

	return 0;
}

猜你喜欢

转载自blog.csdn.net/a1097304791/article/details/86706500