UVALive 6609(Minimal Subarray Length)维护递增序列|RMQ

题意:给一个整数序列(可能有负数),求最短的连续序列使得序列之和大于等于整数x;

解法:第一种是On的复杂度:

我们要的是sum[j]-sum[i]>=x,如果有两个决策j < j‘,而且sum[j] >= sum[j‘],那么j就是没用的。即维护一个sum[j]递增序列。然后每次可以二分查找,但是这里有个特点就是要得到最近的,可以同时维护一个left指针,left指针用于跟进更行答案的左边界,因为维护的单调栈不会再右移到left左边去了(因为如果left右边还可以更新的答案肯定没有当前的小了)。

第二种是RMQ的做法,比较好理解:枚举i,然后求sum[j]-sum[i]>=x最小的j,那么就二分查找j。总复杂度nlogn

第一份代码:

/******************************************************
* author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>
//freopen ("in.txt" , "r" , stdin);
using namespace std;

#define eps 1e-8
const double pi=acos(-1.0);
typedef long long LL;
const int Max=500100;
const int INF=1000000007;

int n,x;
LL num[Max];
LL que[Max];
LL sum[Max];
int increase[Max];

int main()
{
    int t;cin>>t;
    while(t--)
    {
        scanf("%d%d",&n,&x);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",num+i);
            sum[i]=sum[i-1]+num[i];
        }
        int right=1;
        increase[0]=1;
        int left=0;
        int ans=n+1;
        for(int i=2;i<=n;i++)
        {
            while(right>left&&sum[increase[right-1]]>=sum[i])
                right--;
            increase[right++]=i;
            while(right>left+1&&sum[i]-sum[increase[left]]>=x)
            {
                ans=min(ans,i-increase[left]);
                left++;
            }
        }
        if(ans==n+1)
            cout<<"-1\n";
        else
            cout<<ans<<‘\n‘;
    }
}

第二份代码:

/******************************************************
* author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>
//freopen ("in.txt" , "r" , stdin);
using namespace std;

#define eps 1e-8
const double pi=acos(-1.0);
typedef long long LL;
const int Max=500100;
const int INF=1000000007;
int n,x;
LL dp[Max][30];
int mm[Max];
//初始化RMQ, b数组下标从1开始,从0开始简单修改
void RMQ(int n,LL b[])
{
    mm[0] = -1;
    for(int i = 1; i <= n; i++)
    {
        mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
        dp[i][0] = b[i];
    }
    for(int j = 1; j <= mm[n]; j++)
        for(int i = 1; i + (1<<j) -1 <= n; i++)
            dp[i][j] = max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
//查询最大值
LL query(int x,int y)
{
    int k = mm[y-x+1];
    return max(dp[x][k],dp[y-(1<<k)+1][k]);
}
LL num[Max];
LL sum[Max];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        scanf("%d%d",&n,&x);
        for(int i=1; i<=n; i++)
            scanf("%lld",num+i),sum[i]=sum[i-1]+num[i];
        RMQ(n,sum);
        int ans=n+3;
        for(int i=0; i<n; i++)
        {
            int l=i+1,r=n;
            while(l<r)
            {
                int mid=(l+r)/2;
                if(query(i+1,mid)-sum[i]>=x)
                    r=mid;
                else
                    l=mid+1;
            }
            if(sum[r]-sum[i]>=x)
                ans=min(ans,r-i);
            if(sum[l]-sum[i]>=x)
                ans=min(ans,l-i);
        }
        if(ans==n+3)
            ans=-1;
        cout<<ans<<endl;
    }
    return 0;
}

UVALive 6609(Minimal Subarray Length)维护递增序列|RMQ

时间: 2024-11-20 01:42:01

UVALive 6609(Minimal Subarray Length)维护递增序列|RMQ的相关文章

UVALive 6609 Minimal Subarray Length(RMQ-ST+二分)

题意:给定长度为N的数组,求一段连续的元素之和大于等于K,并且让这段元素的长度最小,输出最小长度即可. 题目链接:UVAlive 6609 做法:做一个前缀和prefix,然后再作一个维护前缀和最大值数组Max,枚举所有可能的起始点i,在Max上二分末尾位置r,由于Max维护的是前缀和的最大值,因此具有单调性,可以进行二分,似乎还有其他O(n)的做法,有空去膜一下 代码: #include <stdio.h> #include <bits/stdc++.h> using names

UVA 12697 Minimal Subarray Length

Minimal Subarray Length Time Limit: 3000ms Memory Limit: 131072KB This problem will be judged on UVALive. Original ID: 660964-bit integer IO format: %lld      Java class name: Main You are given an integer sequence of length N and another value X. Yo

最长递增子序列(输出最长递增序列 及其长度)

最长递增子序列的解法有很多种,常用的有最长公共子序列法.动态规划.记录所有递增序列长度最大值的方法. 最长公共子序列法:如例子中的数组A{5,6, 7, 1, 2, 8},则我们排序该数组得到数组A‘{1, 2, 5, 6, 7, 8},然后找出数组A和A’的最长公共子序列即可.显然这里最长公共子序列为{5, 6, 7, 8},也就是原数组A最长递增子序列. 在http://blog.csdn.net/yysdsyl/article/details/4226630中有详细解释. 动态规划:参见h

LeetCode 674. 最长连续递增序列(Longest Continuous Increasing Subsequence) 18

674. 最长连续递增序列 674. Longest Continuous Increasing Subsequence 题目描述 给定一个未经排序的整型数组,找到最长且连续的递增序列. Given an unsorted array of integers, find the length of longest continuous increasing subsequence (subarray). 每日一算法2019/5/21Day 18LeetCode674. Longest Conti

LeetCode 674. Longest Continuous Increasing Subsequence最长连续递增序列 (C++/Java)

题目: Given an unsorted array of integers, find the length of longest continuous increasing subsequence (subarray). Example 1: Input: [1,3,5,4,7] Output: 3 Explanation: The longest continuous increasing subsequence is [1,3,5], its length is 3. Even tho

得到最长连续递增序列

今天作死,看到别人发出来的笔试题就开干了,这tmd还理解错题目了,连续递增序列理解成上一个=下一个-1了. 这是我的成果,撸了4个多小时的: public class Test12 { public static void main(String[] args){ /** * 需求:找出最长的连续递增序列 * 步骤: * 1.找出所有连续序列可能结果,删除不是连续递增序列的,加入集合 * 2.集合排序,取第一个 * * 方式2: * 0.默认len为数组长度 * 1.找出数组中长度为len的序列

矩形网格中寻找最长递增序列

在矩形网格中寻找最长的递增序列 比如如下网格 97,47,56,36 35,57,41,13 89,36,98,75 25,45,26,17 结果要求输出 17, 26, 36, 41, 47, 56, 57, 97 基本想法就是对图中的每一个点都当作起始点试一编 将序列最长的保存起来 最后输出 代码如下 使用java编写 import java.util.ArrayList; public class 最长递增序列 { static int[][] rect={ {97,47,56,36},

POJ 2533 Longest Ordered Subsequence 最长递增序列

Description A numeric sequence of ai is ordered if a1 < a2 < ... < aN. Let the subsequence of the given numeric sequence (a1, a2, ..., aN) be any sequence (ai1, ai2, ..., aiK), where 1 <= i1 < i2 < ... < iK <= N. For example, seque

数据结构与算法学习之路:LIS——最长递增序列的动态规划算法和二分思想算法

一.最长递增序列的问题描述: 求一个整数序列的最长递增子序列,子序列不要求是连续的.例如: Input:4,6,9,6,7,6,3,8,10:Output:5 二.解决方法: 1.用动态规划的方法解决.从问题我们可以知道,我们最终得到的最长递增子序列,其任意一段子序列也是对应序列中的最长子序列.这样说可能不好理解,就以上面的例子来说: 最长子序列为:4,6, 7, 8, 10.在这段子序列的子序列里选一个,例如:4,6,7.则4,6,7也是4,6,9,6,7,6,3这段序列的最长子序列. 对于动