链接:http://poj.org/problem?id=1631
题意:最长上升子序列。复杂度为O(n*logn).
思路:这道题只能用nlogn的算法,n^2的话会卡掉。
下面这两个个链接介绍nlogn的算法讲的还可以。
http://www.cnblogs.com/celia01/archive/2012/07/27/2611043.html
http://blog.sina.com.cn/s/blog_4b1e4fe9010098af.html
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int maxn=40005; int n,a[maxn],d[maxn]; int binarysearch(int l,int r,int p) { int mid=(l+r)/2; while(l<=r) { if(d[mid]<p && p<=d[mid+1]) return mid; if(d[mid]<p) l=mid+1; else r=mid-1; mid=(l+r)/2; } } int solve() { int len=1; d[1]=a[1]; for(int i=2;i<=n;i++) { if(a[i]>d[len]) { len++; d[len]=a[i]; } else { int k=binarysearch(1,len,a[i]); d[k+1]=a[i]; } } return len; } int main() { // freopen("ine.cpp","r",stdin); int t; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); printf("%d ",solve()); } return 0; }
上面这个写法比较好懂,《训练指南》上讲了另一种写法,短了很多。
如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int maxn=40005; const int INF=1000000; int n,a[maxn],d[maxn]; int main() { // freopen("ine.cpp","r",stdin); int t; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); fill(d,d+n,INF); for(int i=1;i<=n;i++) *lower_bound(d,d+n,a[i])=a[i]; printf("%d ",lower_bound(d,d+n,INF)-d); } return 0; }
上面使用的STL中的fill()函数和lower_bound()函数。
简略简绍下。
fill()函数它的原理是把那一块单元赋成指定的值,与memset不同,
memset则是按字节填充的。
例如:
int main() { int d[100]; fill(d,d+100,1); for(int i=0; i<100; i++) cout<<d[i]<<" "; cout<<endl; memset(d,1,100*sizeof(int)); for(int i=0; i<100; i++) cout<<d[i]<<" "; cout<<endl; }
使用fill()函数,数组d[]中的元素都赋值为数字1,使用memset()函数,数组d[]中的元素都赋值为数字(1<<24)+(1<<16)+(1<<8)+1 = 16843009.
iterator lower_bound( const key_type &key ): 返回一个迭代器,指向键值>= key的第一个元素。
iterator upper_bound( const key_type &key ):返回一个迭代器,指向键值> key的第一个元素。
lower_bound()在 [first , last) 这个前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置。(注意:此时数组下标越界)
upper_bound()也是在 [first , last) 这个前闭后开区间进行二分查找,如果插入元素大于数组中全部元素,返回的是last。(注意:此时数组下标越界)