LIS问题
LIS问题是经典的DP问题,设F[i]为以i结尾的LIS长度,转移方程为:
F[i]=max(0,F[j] | i>j,A[i]>A[j])+1
不难看出这样的复杂度是O(n^2)的,有的时候实在难以承受。
实际上LIS问题存在O(nlogn)的算法
首先我们肯定这样一个事实:
对于F[i]=F[j],且A[i]小于A[j],则我们可以发现 i 绝对比 j 好。
所以我们设g[k]为F=k的最小A(不存在设为INF),不难发现g是单调递增的(否则不符合g的定义)
所以我们在计算F数组时,可以在g中二分查找最后一个j,使A[i]>A[j],则将i作为j的后续状态一定是最优的。
然后我们再用 i 更新 j+1,所以算法压缩到了O(nlogn)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
#define read(x) scanf("%d",&x)
using namespace std;
const int maxn=100000+10;
const int INF=(1<<31)-1;
int n,a[maxn],d[maxn],g[maxn];
int main()
{
read(n);
rep(i,1,n)
read(a[i]);
rep(i,0,n) g[i]=INF;
rep(i,1,n)
{
int k=lower_bound(g+1,g+n+1,a[i])-g; //在所有g中二分查找
d[i]=k;
g[k]=a[i]; //更新g数组
}
int ans=0;
rep(i,1,n)
ans=max(d[i],ans);
printf("%d\n",ans);
return 0;
}

浙公网安备 33010602011771号