zoukankan      html  css  js  c++  java
  • 最长上升子序列nlogn算法

    LIS问题是经典的动态规划问题,它的状态转移相信大家都很熟悉:

    f[i] = f[k] + 1  (k < i 且 A[k] < A[i])

    显然这样做复杂度是O(n^2)

    有没有更快的算法呢?

    当然,你会发现你在往前找的过程中实际上就是在查询最大值的过程,如果能应用二分就很有机会降到nlogn

    但是原f[]序列并不满足二分性质呐。。怎么办呢?


    我们要的是往前长度最大的,我们的二分目标就是长度

    不妨开一个长度数组len[i],表示长度为i的上升子序列最后末尾的值的最小值

    对于没算出的len,设为INF,每次算完f[i]后,就对len[f[i]]进行更新

    这样子我们就可以每次logn算出f[i]


    为什么这样是正确的呢?

    应为len[]数组是单调递增的,长度为2的末尾值一定比长度为3的要小,所以我们写的二分一定是最大值的二分


    fill(len,len + maxn,INF);
    	len[0] = 0;
    	int ans = 0;
    	REP(i,n){
    		//cout<<A[i]<<' ';
    		int L = 0,R = ans;
    		while (L < R){
    			int mid = (L + R + 1) >> 1;
    			if (len[mid] < A[i]) L = mid;
    			else R = mid - 1;
    		}
    		f[i] = L + 1;
    		len[f[i]] = min(len[f[i]],A[i]);
    		ans = max(ans,f[i]);
    	}
    	cout<<ans<<endl;




  • 相关阅读:
    NCPC2016
    2016 ACM-ICPC CHINA-Final
    2016沈阳区域赛题解
    NAIPC2016部分题解
    Gym
    数论之莫比乌斯反演
    2018 多校 HDU
    LightOJ
    LightOJ
    java操作XML---XML基础知识
  • 原文地址:https://www.cnblogs.com/Mychael/p/8282834.html
Copyright © 2011-2022 走看看