您的位置:首页 > 其它

最长不下降子序列

2016-05-20 15:55 363 查看
问题描述:在序列A中,选出子序列B,使B [ i ]>=B [ i-1 ],即不下降子序列,然后输出序列A中所有的不下降子序列中最长的长度。
数据范围:80%的数据 序列A的长度<=1000。A[ i ]<=100000。 100%的数据 序列A的长度<=100000。A[ i ]在int范围内。【解决方法1】(80%的数据) 很明显,可以用动归来解决这个问题,设f [ i ] 为序列A从i到n的最长不下降子序列的长度。那么,就扫描i后面的f [ j ],当A [ j ]>=A [ i ]时,取最大值。 可以得出动态方程:f [ i ]=max(f[ j ]+1:i<j&A[ j ]>=A[ i ])。最后取f [ i ]的最大值。时间复杂度是O ( n*n ) 。
#include<cstdio>
#include<iostream>
using namespace std;
int a[100007],f[100007];
int ans,n;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=n;i>=1;i--)
{
f[i]=1;
for(int j=i+1;j<=n;j++)
if(a[j]>=a[i] && f[j]+1>f[i]) f[i]=f[j]+1;
ans=max(f[i],ans);
}

printf("%d",ans);
return 0;

}
那么,如何才能获得100%的数据呢?【解决方法2】 因为这是取其最大值的,所以,我们很容易就想到用线段树或树状数组。但是,如果不做一些优化的话,线段树的空间就是max(A[ i ]),如果A[ i ]太大,那就绝对是做不了的。这时,我们可以将数据离散化!如数据{23,5,86,3,27364391},离散化后就变成了{3,2,4,1,5},空间只需O(n)。 而离散化就只需要一个计数排序或快速排序即可,时间复杂度是O(n)或O(n logn)。离散化以后,就可以进行线段树的相关操作了。时间复杂度是O(n longn)。因此,总时间也就是O(n longn)。下面给出程序:
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
int n;
int t[100007];

struct Tnode{
int lc,rc;
int max;
int l,r;
}f[100000];

struct data{
int num,h;
};
data a[100007],b[100007];

int root,fp=0;

int _cmp(data a,data b)
{
return a.num<b.num;
}

int getPoint(int l,int r)
{
fp++;
f[fp].l=l;
f[fp].r=r;
f[fp].max=0;
return fp;
}
int create(int l,int r)
{
int now=getPoint(l,r);
if(l<r)
{
f[now].lc=create(l, ( l+r )/2 );
f[now].rc=create( ( l+r )/2+1, r );
}
return now;
}//建树

int query(int root,int l,int r)
{
if(f[root].l>r || f[root].r<l) return 0;

if (l<=f[root].l && r>=f[root].r) return f[root].max;

return max(query(f[root].lc,l,r) , query(f[root].rc,l,r));
}

void update(int root,int p, int v)
{
int l=f[root].l , r=f[root].r;
if(p<l || p>r) return;

if(l==r)
{
f[root].max=v;
return;
}

update(f[root].lc,p,v);
update(f[root].rc,p,v);

f[root].max=max(f[ f[root].lc ].max , f[ f[root].rc ].max);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{

scanf("%d",&a[i].num);
b[i].h=i;
b[i].num=a[i].num;

}

sort(b+1,b+n+1,_cmp);//排序

root=create(1,n);//建树

for(int i=1;i<=n;i++) a[ b[i].h ].h=i;//离散化

int maxx=0;
for(int i=1;i<=n;i++)
{

t[i]=query(root,1,a[i].h-1)+1;
update(root,a[i].h,t[i]);

maxx=max(maxx,t[i]);
}

printf("%d",maxx);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: