题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1950
读完题意你会发现这是一道LIS(最长上升子序列)裸题
但n有点大 o(n^2)肯定超时
这里我们就要采取nlogn的算法了
设dp[i]为长度为i的上升子序列的末元素
设len为我们要的答案
初始化 len=1,dp[1]=a[i]
for(int i=2;i<=n;i++)
如果 a[i]>=dp[len]那么我们可以把a[i]放在最长的上升子序列(dp[len])的末尾 更新----->dp[++len]=a[i];
如果a[i]<dp[len] 那么我们要从dp[1]-dp[len-1]找到最大的一个不大于a[i]的数的位置 记为pos 那么我们可以把a[i]放在其后末尾 更新--->dp[pos+1]=a[i];
大概知道了原理 就看一下代码然后自己写吧。
AC代码如下:
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int maxn=50005; int dp[maxn],a[maxn],n,len; int binarysearch(int value)//找到第一个大于或等于自己的数的位置 { int left=1,right=len-1,mid; while(left<right) { mid=(left+right)>>1; if(value>dp[mid])left=mid+1; else right=mid-1; } if(dp[left]<value)return left+1; return left; } int main() { int T; cin>>T; while(T--) { cin>>n; memset(a,0,sizeof(a)); memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++)cin>>a[i]; len=1; dp[len]=a[1]; for(int i=2;i<=n;i++) { if(a[i]>=dp[len]) { dp[++len]=a[i]; } else { int pos=binarysearch(a[i]); //printf("a[%d]=%d",i,a[i]); //printf(" pos=%d\n",pos); dp[pos]=a[i]; //printf(" so dp[%d]=%d\n",pos,dp[pos]); } //printf("dp[%d]=%d\n",len,dp[len]); } cout<<len<<endl; } }