题目:http://poj.org/problem?id=1631
两种nlogn的方法。
1.树状数组优化暴力。有种扫描线的感觉,以时间保证位置,把值作为数组脚标。
2.记录长为...的上升子序列末尾元素最小值;如果新入元素a比d [ top ]大,就d [ ++top ] = a,否则二分查找第一个d的值大于a的地方,用a更新该d。答案为top。
二分的边界之类的需注意。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int t,n,a,d,f[40005],ans; int query(int k) { int ret=0; while(k) { ret=max(ret,f[k]); k-=k&-k; } return ret; } void add(int k) { while(k<=n) { f[k]=max(f[k],d); k+=k&-k; } } int main() { scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a); d=query(a)+1; ans=max(ans,d); add(a); } printf("%d ",ans); ans=0; memset(f,0,sizeof f); } return 0; }
#include<iostream> #include<cstdio> using namespace std; int t,n,a,d[40005],l,r,ret,top; int main() { scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a); if(a>d[top]) { d[++top]=a;continue; } l=1;r=top;ret=-1; while(l<r)//////// { int mid=(l+r)/2; if(d[mid]>a)ret=mid,r=mid; else l=mid+1; } if(d[l]>a)ret=l;/////// d[ret]=a; } printf("%d ",top); top=0; } return 0; }