WEEK10作业-B-LIS&LCS

题意

东东有两个序列A和B。
他想要知道序列A的LIS和序列AB的LCS的长度。
注意,LIS为严格递增的,即a1<a2<…<ak(ai<=1,000,000,000)。
Input
第一行两个数n,m(1<=n<=5,000,1<=m<=5,000)
第二行n个数,表示序列A
第三行m个数,表示序列B
Output
输出一行数据ans1和ans2,分别代表序列A的LIS和序列AB的LCS的长度

Simple Input
5 5
1 3 2 5 4
2 4 3 1 5
Simple Output
3 2

思路

先说LIS,处理有三种方法。分别是O(n^2)的DP,O(nlogn)的二分+贪心法,以及O(nlogn)的树状数组优化的DP,本次我用的是二分加贪心的方法,复杂度少一些。
未使用树状数组优化的DP:
状态:定义fi表示以A;为结尾的最长上升序列的方程。
初始化: f1=1
转移过程fi=max{fi| j<i^Aj< Ai}+1
输出答案: max{f[i], i=1…n}
时间复杂度: 0(n^2)
核心代码:

for(int i=1; i<=n; i++)        
for(int j=1; j<i; j++)            
if(a[j] < a[i])                
f[i] = max(f[i], f[j]+1);

我用的二分加贪心的方法,复杂度为O(nlogn)。新建一个 low 数组,low [ i ]表示长度为i的LIS结尾元素的最小值。贪心准则为:对于一个上升子序列,其结尾元素越小,越有利于在后面接其他的元素,也就越可能变得更长。因此,我们只需要维护 low 数组,对于每一个a[ i ],如果a[ i ] > low [当前最长的LIS长度],就把 a [ i ]接到当前最长的LIS后面,即low [++当前最长的LIS长度] = a [ i ]。 否则,在low数组中找到第一个大于等于a [ i ]的元素low [ j ],用a[i]去代替这个元素。当然,这个元素的查找如果用遍历的话复杂度还是O(N^2),所以我们用二分法查找。
关于LCS,我用的就是动态规划的方法,复杂度O(nm)。
设计状态:假设f[i][j]为A, A2, … A;和B1, B2, …的LCS长度
初始化:初始f[1][0]= f[0][1] = f[0][0] = 0
转移方程:当Ai== Bj时, f[i][j] = f[i-1][j-1] + 1
否则f[i][j] =max(f[i-1][j], f[i][j-1])
输出答案: f[n][m]
时间复杂度: O(nm)
还有O(mlogn)的方法,就是转化为LIS问题进行处理。记录a中每个元素在b中出现的位置, 再将位置按降序排列。将a中每个元素的位置按a中元素的顺序排列成一个序列c,对c求LIS即可,证明的话太难理解,所以我没用这种方法。

代码

#include<cmath>
#include<stdio.h>
#include <iostream>
#include <algorithm>
#define maxn 5010 
#define inf 1e10
#define ll long long
using namespace std;
ll low[maxn],a[maxn],b[maxn];
int f[maxn][maxn];
int n,m,ans1,ans2;
void LIS(){
	low[1]=a[1]; 
    ans1=1;  
    for(int i=2; i<=n; i++)
    {
        if(a[i]>low[ans1])    
            low[++ans1]=a[i];
        else
            low[lower_bound(low,low+ans1,a[i])-low]=a[i];
    }
    cout<<ans1<<" ";
}
void LCS(){
   for (int i=1; i<=n; i++){
        for (int j=1; j<=m; j++){
            if(a[i]==b[j]) f[i][j]=f[i-1][j-1]+1;
            else f[i][j]=max(f[i-1][j],f[i][j-1]);
        }
    }
    ans2=f[n][m];
    cout<<ans2<<endl;
}
int main()
{
    cin>>n>>m;
    for(int i=1; i<=n; i++) 
    {
        cin>>a[i]; 
        low[i]=inf;   
    }
    for(int i=1;i<=m;i++)
    {
    	cin>>b[i];
    	f[0][i]=0;
    	f[i][0]=0;
	}
	f[0][0]=0;
    LIS();
    LCS();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值