2188 最长上升子序列

来源:互联网 发布:excel筛选两表重复数据 编辑:程序博客网 时间:2024/06/07 01:04
2188 最长上升子序列 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 钻石 Diamond题目描述 DescriptionLIS问题是最经典的动态规划基础问题之一。如果要求一个满足一定条件的最长上升子序列,你还能解决吗?给出一个长度为N整数序列,请求出它的包含第K个元素的最长上升子序列。例如:对于长度为6的序列<2,7,3,4,8,5>,它的最长上升子序列为<2,3,4,5>,      但如果限制一定要包含第2个元素,那么满足此要求的最长上升子序列就只能是<2,7,8>了。输入描述 Input Description第一行为两个整数N,K,如上所述。接下来是N个整数,描述一个序列。输出描述 Output Description请输出两个整数,即包含第K个元素的最长上升子序列长度。样例输入 Sample Input8 665 158 170 299 300 155 207 389样例输出 Sample Output4数据范围及提示 Data Size & Hint80%的数据,满足0<n<=1000,0<k<=n100%的数据,满足0<n<=200000,0<k<=n******************************数组处理+DP+二分查找 #include<iostream>#include<cstring>#include<cstdio>#include<algorithm>using namespace std;int f[200010],a[200010],b[200010];int main(){memset(f,0,sizeof(f));int i,j,n,k,maxf,ans = 0;int count = 1;cin>>n>>k;for(i = 1; i <= n; i++){cin>>a[i];}for(i = 1; i < k; i++)           //形成b,新数组 {if(a[i] < a[k]){b[count++] = a[i];}}b[count++] = a[k];for(i = k+1; i <= n; i++){if(a[i] > a[k]){b[count++] = a[i];}}count--;                        //形成b,新数组 memset(a,0,sizeof(a));a[1] = b[1];                     //a[l]记录长度为l的子串末数字最小值,是个递增数组f[1] = 1;int left,right,len = 1,mid,pos;for(i = 2; i <= count; i++){/*maxf = 0;for(j = i+1; j <= n; j++)        //其实这里实质是 查找 !!可优化!!{if(b[i] < b[j] && f[j] > maxf){maxf = f[j];}}f[i] = maxf + 1;*/left = 1 , right = len;pos = 0;while(left <= right){mid = left + (right-left)/2;if(a[mid] < b[i]){pos = mid;left = mid+1;}else{right = mid-1;}}f[i] = pos + 1;if(f[i] > len) len = f[i];a[f[i]] = b[i];/*    理解: 假设序列为 27 489 1996 423 ,当i = 4时          d[2] = 489 , d[1] = 27,则二分查找出来的f[i] = pos + 1 = 1 + 1 = 2;  ∵ ↑ 不为0且leni = 2 这个值再现了  ∴这个b[4]肯定是比之前的d[f[i]]小的,所以直接a[f[i]] = b[i];  依此类托,便可知为什么不需要下面的判断:   if(a[f[i]])                    a[f[i]] = min(a[f[i]],b[i]);                else                    a[f[i]] = b[i]; */ }cout<<len<<endl;return 0;}
************************************************************************可供吐槽
0 0
原创粉丝点击