最长不下降子序列
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 ) 。
数据范围: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; }
相关文章推荐
- 逆序对
- 二叉堆
- USACO 2016 JAN——Angry Cows套题的解题报告
- 2009南海区集训队初中选拔题1的解题报告
- 2016.3.13的解题报告
- 全排列
- 2016.3.20的解题报告
- 【编程技巧】——加快cin的输入速度
- 【编程技巧】——对拍
- RMQ
- 【编程技巧】——计算时间
- 2016GDOI市选拔赛解题报告
- 【转载】胜者树
- 【转载】计算几何中的精度问题(转)
- USACO 2016 open Bronze 解题报告
- SPFA
- USACO 2016 open Silver 解题报告
- 2016GDOI的总结
- 六十一 Web开发 使用Web框架
- js判断 微信浏览器 或者 QQ内置浏览器