动态规划入门 COGS1398 最长上升子序列
1398. 最长上升子序列
★ 输入文件:lis1.in
输出文件:lis1.out
简单对比
时间限制:1 s 内存限制:256 MB
【题目描述】
设有整数序列A[1],A[2],A[3],…,A[m],若存在下标i1<i2<i3<…<in,且A[i1]<A[i2]<A[i3]<…<A[in],则称 序列A[1],A[2],A[3],…,A[m]中有长度为n的上升子序列A[i1] , A[i2] ,A[i3] ,…,A[in]。
请编程计算指定序列的最长上升子序列长度。
【输入格式】
第一行一个正整数n(n<1001),表示序列中整数个数;
第二行是空格隔开的n个整数组成的序列。
【输出格式】
一个正整数,表示输入文件中整数序列的最长上升子序列的长度。
【样例输入】
7
1 7 3 5 9 4 8
【样例输出】
4
【样例说明】
- 序列(1,7,3,5,9,4,8)最长上升序列有:(1,3,5,9),(1,3,5,8),(1,3,4,8),他们长度为4。
- 方程为f(i)=max{f(j)}+1(b
j
- <b
i
- 且i<j)
- 这个题重在优化
- 首先先贴LIS代码
- 注意要赋到f[]数组初值(某小受就没有)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 using namespace std; 6 7 int n; 8 int in[10010],f[10010]; 9 int ans; 10 11 int main(){ 12 scanf("%d",&n); 13 for(int i=1;i<=n;i++) scanf("%d",&in[i]),f[i]=1; 14 for(int i=2;i<=n;i++){ 15 for(int j=1;j<i;j++) 16 if(in[i]>in[j]) f[i]=max(f[i],f[j]+1); 17 ans=max(ans,f[i]); 18 } 19 printf("%d",ans); 20 return 0; 21 }
单调栈优化
从前向后扫描序列列,维护一个单调栈
插⼊入一个数时,我们在h[] 中二分出一个位置i,使得h[i]<a[k+1]<=h[i + 1],令h[i+1]=a[k + 1] 即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 7 int n; 8 int num[10010]; 9 int top; 10 int tmp; 11 12 void add(int t){ 13 if(t>num[top]) num[++top]=t; 14 else{ 15 int ll=1; 16 int rr=top; 17 int mid; 18 while(ll<=rr){ 19 mid=(ll+rr)>>1; 20 if(t>num[mid]) ll=mid+1; 21 else rr=mid-1;//注意-1和+1 22 } 23 num[ll]=t; 24 } 25 return; 26 } 27 28 int main(){ 29 scanf("%d",&n); 30 num[0]=-1; 31 for(int i=1;i<=n;i++) scanf("%d",&tmp),add(tmp); 32 printf("%d",top); 33 return 0; 34 }
树状数组优化
数组离散化并用树状数组维护前缀最大值
1 //实为最长上升子序列 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 8 int n; 9 int in[10010],val[10010]; 10 int len; 11 int b[10010];//b[i]以数字i结尾的子序列最长可以为的值 12 //扫描到in[k]这个位置时,b[i]中只有b[a[k]]会改变 13 //b[a[k]]=max(b[i]+1|i<a[k]) 14 int ans,temp; 15 16 void add(int v,int pos){ 17 for(int i=pos;i<=len;i+=i&(-i)) b[i]=max(v,b[i]); 18 return; 19 } 20 21 int ask(int pos){ 22 int t=0; 23 for(int i=pos;i;i-=i&(-i)) t=max(t,b[i]); 24 return t; 25 } 26 27 int main(){ 28 scanf("%d",&n); 29 for(int i=1;i<=n;i++) scanf("%d",&in[i]),val[i]=in[i]; 30 sort(val+1,val+n+1); 31 len=unique(val+1,val+n+1)-val;//去重 保证最长上升 32 memset(b,0,sizeof(b)); 33 ans=1; 34 for(int i=1;i<=n;i++){ 35 in[i]=lower_bound(val+1,val+len+1,in[i])-val+1;//离散化???高大上 36 temp=ask(in[i]-1)+1; 37 ans=max(ans,temp); 38 add(temp,in[i]); 39 } 40 printf("%d",ans); 41 }
线段树优化
可以用树状数组优化,那么显然可用线段树
然而我码了2K挂掉了,以后再补