您的位置:首页 > 其它

51nod 40 选择子序列 单调栈+DP

2017-12-30 20:02 197 查看
题意:长度为n的序列a.每个数都不相同. 

找到一个序列b 0<=b[i]<n.并且序列b满足: A[b[0]]> A[b[1]]> ...A[b[k]]. 

并且:A[j]<A[b[i+1]]. (min(b[i],b[i+1]) <j <max(b[i],b[i+1])) 

n<=5e4,a[i]<=1e9 问序列b的长度最长为?

a[b[i]]要大于(a[b[i]]~a[b[i-1]])之间的数. 

选下一个数,可以在上一个数的左右两边 而且不知道要选哪一个 不好处理.

先保存每个数的下标 然后将序列按照权值从大到小排序.

设dp[i]为以排序后下标i结尾 选出最长序列的长度.

因为j<i a[j]>a[i] 如果 b[j]~b[i]之间没有出现以前出现过的下标则.

dp[i]=max(dp[i],dp[j]+1) O(n^2 logn).

..1.11. X..1..1...

对于某个下标编号为X 其实它只能跟在X左边第一比它大的和X往右第一个比它大的后面.
用单调栈预处理后 在DP一次即可 O(N+NlogN).

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e4+5;
struct node{
int x,id;
}a
;
bool cmp(node a,node b)
{
return a.x>b.x;
}
int n,dp
,c
;
int le
,rg
;
stack<int> s;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i].x,a[i].id=i;
while(!s.empty()&&a[s.top()].x<a[i].x)
rg[s.top()]=i,s.pop();
if(!s.empty())
le[i]=s.top();
s.push(i);
}
sort(a+1,a+1+n,cmp);
int res=1;
for(int i=1;i<=n;i++)
{
int j=a[i].id,x=le[j],y=rg[j];

4000
dp[j]=1;
if(x)
dp[j]=max(dp[j],dp[x]+1);
if(y)
dp[j]=max(dp[j],dp[y]+1);
res=max(res,dp[j]);
}
printf("%d\n",res);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: