题意 给出一个序列 问它的最长严格上升子序列多长 这个序列中的0可以被替代为任何数
n的范围给出了1e5 所以平常的O(n*n)lis不能用了
在kuangbin的模板里有O(nlogn)的模板 套上就可以过了
但是比赛的时候没有拿模板= =. 于是就想出了另外一个时间复杂度不明的办法= =.
将序列从前往后扫
设定一个数组a a[i]=z a[i]为当前i长度的上升子序列中的最小的尾数的大小 maxl为当前找出的最长的子序列长度
每次我们扫到一个数 都对0-maxl长度的a[i]进行判断 看能不能将他加到长度为i-1的序列的尾部 来优化a[i]使长度为i的序列的尾数更小
当遇到非0数的时候 只需要慢慢判断就好了 遇到0的时候 应当尽量的使0变换的数更小 则在优化的时候应当将0变为a[i-1]+1来与a[i]比较
最后的maxl即为答案
这个办法速度并不稳定 因为每次都要从0-maxl扫一遍 最差的时候是O(n*n)(当所给序列为上升序列时)
#include<stdio.h> #include<string.h> #include<algorithm> #include<map> #include<math.h> #include<iostream> using namespace std; int n; int a[100050]; /// every l - min wei int maxl; int main() { int t; scanf("%d",&t); int tt=0; while(t--) { tt++; maxl=0; a[0]=-999999999; scanf("%d",&n); for(int i=1;i<=n;i++) { int x; scanf("%d",&x); if(x!=0) { if(x>a[maxl]){ maxl++; a[maxl]=x; } for(int k=maxl;k>=2;k--) { if(x>a[k-1]&&x<a[k]) a[k]=x; } if(x<a[1]) a[1]=x; } else { maxl++; a[maxl]=a[maxl-1]+1; for(int k=maxl-1;k>=1;k--) { if(a[k]>a[k-1]+1) a[k]=a[k-1]+1; } } } printf("Case #%d: ",tt); printf("%d\n",maxl); } }
时间: 2024-10-05 05:26:17