题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1153点击打开链接
长度为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示例
15 9 10 2 -1 3 -5 0 -3 1 12 5 8 -2 6 4
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;
}