AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

《挑战程序设计竞赛》poj 3061 Subsequence 二分 前缀和 双指针 一些基础算法

作者: 作者的头像   itdef ,  2019-12-18 18:51:09 ,  所有人可见 ,  阅读 1052


2


2

地址 http://poj.org/problem?id=3061
111.png

解法1

使用双指针

由于序列是连续正数

使用l r 表示选择的子序列的起始

每当和小于要求的时候 我们向右侧扩展 增大序列和

每当和大于等于要求的时候 我们将子序列左边的数字剔除 看能是在减少长度情况下 还能保持子序列和满足要求

这样在指定起点下的满足要求的最短子序列和都会被记录 然后在比较出最短长度的子序列

如图2222.png

#include <iostream>
#include <vector>
#include <algorithm>
#include <memory.h>
#include <queue>


using namespace std;


/*
Sample Input
6
10 15
5 1 3 5 10 7 4 9 2 8
5 11
1 2 3 4 5
1 2
1
1 1
5
3 9999
1 2 3 
3 0
1 2 3 

Sample Output
2
3
*/
const int MAX_N = 1000010;
int n, m;
int nums[MAX_N];

int ret = MAX_N;

void solve()
{
    int sum = 0;
    int minlen = MAX_N;

    int r = -1; int l = 0;

    while (1) {
        if (sum < m) {
            r++;
            if (r >= n) break;
            sum += nums[r];
        }
        else {
            //sum >= m
            minlen = min(minlen, r - l + 1);
            sum -= nums[l];
            l++;
            if (l >= n) break;
            if (l > r) {
                r = l;
                sum = nums[l];
            }
        }
    }


    if (minlen == MAX_N) minlen = 0;
    cout << minlen << endl;
}


int main()
{
    int loop;
    cin >> loop;
    while (loop--) {
        cin >> n >> m;

        for (int i = 0; i < n; i++) {
            cin >> nums[i];
        }
        ret = MAX_N;
        solve();
    }

    return 0;
}

//=========================================================================================

解法2 二分查找前缀和
使用前缀和就可以快速定位各个子序列的和

然后使用二分查找进行查找以指定索引开始的子序列满足和要求的最短长度

最后得到所有满足需求中最短的子序列长度

代码如下

#include <iostream>
#include <algorithm>

using namespace std;

const int MAX_N = 1000010;
int n, m;
int nums[MAX_N];
int preSum[MAX_N];


int binartSearch(int sum[],int l, int r)
{
    int start = l;
    while (l < r) {
        int mid = (l + r) >> 1;
        if (sum[mid] - sum[start] >= m) {
            r = mid;
        }
        else {
            l = mid + 1;
        }
    }

    return (l-start);
}

int solve()
{
    int     ret = MAX_N;
    for (int i = 1; i <= n; i++) {
        preSum[i] = preSum[i - 1] + nums[i];
    }
    //全部加起来都无法达到标准
    if (preSum[n] < m) return 0;

    for (int i = 1; i < n; i++) {
        //if(preSum[i]+m <= preSum[n]){
        if (preSum[n] - preSum[i] >= m) {
            int idx = binartSearch(preSum,i,n);
            ret = min(ret, idx);
        }
    }

    if (ret == MAX_N) ret = 0;
    return ret;
}


int main()
{
    int loop;
    cin >> loop;

    while (loop--) {
        cin >> n >> m;
        memset(nums,0,sizeof(nums));
        memset(preSum, 0, sizeof(preSum));

        for (int i = 1; i <= n; i++) {
            cin >> nums[i];
        }
        cout << solve() << endl;
    }

    return 0;
}

0 评论

App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息