51Nod

来源:互联网 发布:mysql 查找第一条记录 编辑:程序博客网 时间:2024/05/17 03:34

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1153点击打开链接

1153 选择子序列
题目来源: Codility
基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题
长度为N的整数数组A,所有的数均不相同,假设下标从0开始。找到一个最长的数组B,B数组的长度为K,数值范围是0 - N - 1,记录的是A数组的下标。满足A[B[0]] > A[B[1]] > A[B[2]] >...A[B[K]],并且对任意连续的两项B[i]及B[i + 1],满足min(B[i],B[i + 1]) < j < max(B[i],B[i + 1]) 均有A[j] < A[B[i + 1]] ,求最大的K。例如:9, 10, 2, -1, 3, -5, 0, -3, 1, 12, 5, 8, -2, 6, 4。可以选出:12, 10, 3, 1, 0, -3。对应的下标为:9, 1, 4, 8, 6, 7(就是B数组),输出6。
Input
第1行:一个数N,表示A数组的长度。(1 <= N <= 50000)第2 - N + 1行:每行1个数对应A数组的元素Ai(0 < Ai < 10^9)
Output
输出B数组最长的长度K。
Input示例
159102-13-50-311258-264
Output示例
6


这道题网上的写法很多 单调栈 线段树 dfs。。

一开始想的是单调栈+贪心 单调栈左右扫一遍之后每次选取符合条件且范围最大的加入 但是存在像 1 2 10 3 4 12 9 8 7 6这样的数据 贪心会导致错误的选择

然后因为跟区间有关因此想到线段树 

从小到大依次将每个数的范围的maxx值+1 维护每个区间的最大值

之所以从小到大 这样保证了后面加入的数一定能够包含比他小的数 并且选取的都是最优的路径+1

细想其实不难


#include <bits/stdc++.h>using namespace std;int a[50010];int la[50010];int ra[50010];struct xjy{    int sum;    int num;    bool operator < (const xjy &r)const    {        return  sum > r.sum;    }};struct xjyy{    int left;    int right;    int maxx;};xjyy tree[50010<<2];void build(int i,int left,int right){    if(left==right)    {        tree[i].left=left;        tree[i].right=right;        tree[i].maxx=0;        return;    }    int mid=(left+right)>>1;    build(i<<1,left,mid);    build(i<<1|1,mid+1,right);    tree[i].left=left;    tree[i].right=right;    tree[i].maxx=0;}void update(int i,int left,int right){    if(left==tree[i].left&&tree[i].right==right)    {        tree[i].maxx++;        return;    }    int mid=(tree[i].left+tree[i].right)>>1;    if(right<=mid)        update(i<<1,left,right);    else if(left>mid)        update(i<<1|1,left,right);    else    {        update(i<<1,left,mid);        update(i<<1|1,mid+1,right);    }    tree[i].maxx=max(tree[i<<1].maxx,tree[i<<1|1].maxx);}priority_queue<xjy > q;int main(){    int n;    cin >> n;    for(int i=1;i<=n;i++)        scanf("%d",&a[i]);    stack <int > s;    for(int i=1;i<=n;i++)    {        la[i]=i;        if(s.empty())        {            s.push(i);            la[i]=1;        }        else        {            while(!s.empty())            {                if(a[s.top()]<a[i])                {                    la[i]=la[s.top()];                    s.pop();                }                else                {                    s.push(i);                    break;                }            }            if(s.empty())                s.push(i);        }    }    while(!s.empty())        s.pop();    for(int i=n;i>=1;i--)    {        ra[i]=i;        if(s.empty())        {            s.push(i);            ra[i]=i;        }        else        {            while(!s.empty())            {                if(a[s.top()]<a[i])                {                    ra[i]=ra[s.top()];                    s.pop();                }                else                {                    s.push(i);                    break;                }            }            if(s.empty())                s.push(i);        }    }    build(1,1,n);    for(int i=1;i<=n;i++)        {            xjy mid;            mid.num=i;            mid.sum=a[i];            q.push(mid);        }    while(!q.empty())    {        xjy mid=q.top();        q.pop();        update(1,la[mid.num],ra[mid.num]);    }    cout << tree[1].maxx;}





原创粉丝点击