• 【日记】12.17


    12.17

    洛谷突然黄名?

    DP

    1.洛谷P1020:最长不上升子序列(LNIS)和最小不上升子序列个数。

    首先是LNIS:

    朴素(O(n^2))做法:从后往前,dp[i]=max(dp[i],dp[j]+1),满足i<j&&a[i]>=a[j]。

    快速(O(nlog n))做法:从前往后,每次找到序列中第一个比它小的数,更新优化,具体原理可见:https://blog.csdn.net/wqtltm/article/details/81253935,看图相当不错。同样发现这些数组可以进行复用,因此只需要一个d数组即可,空间复杂度(O(n))

    其次是最小划分出序列的个数。

    有一个Dilworth定理,简单来讲就是,最小不上升子序列个数=最长上升子序列长度(把不去掉,把个数换成长度)。其实感性是可以理解的。

    那么再跑一个LIS即可。

    注意:找第一个比他小的数,可以用upper_bound(a+1,a+n+1,x,greater<int>())来做,不要用lower_bound()+1,容易出锅。小于等于同理。

    #include<bits/stdc++.h>
    using namespace std;
    const int M=1e5+20;
    int cnt,a[M];
    struct LNIS{
    	int dp[M],n;
    	void init(){n=cnt;}
    	void run(){
    		int ans=0;
    		for(int i=n;i>=1;--i){
    			dp[i]=1;
    			for(int j=n;j>=i+1;--j)
    				if (a[i]>=a[j])
    					dp[i]=max(dp[i],dp[j]+1);
    			ans=max(ans,dp[i]);
    		}
    		printf("%d
    ",ans);
    	}
    }L1;
    struct LIS{
    	int dp[M],n;
    	void init(){n=cnt;}
    	void run(){
    		int ans=0;
    		for(int i=1;i<=n;++i){
    			dp[i]=1;
    			for(int j=1;j<=i-1;++j)
    				if (a[i]>a[j])
    					dp[i]=max(dp[i],dp[j]+1);
    			ans=max(ans,dp[i]);
    		}
    		printf("%d
    ",ans);
    	}
    }L2;
    int main(){
    	int c;
    	while(~scanf("%d",&c))
    		a[++cnt]=c;
    	L1.init();
    	L2.init();
    	L1.run();
    	L2.run();
    	return 0;
    }
    

    nlogn做法:

    #include<bits/stdc++.h>
    using namespace std;
    const int M=1e5+20;
    int cnt,a[M];
    struct LNIS{
    	int dp[M],d[M],n;
    	void init(){n=cnt;}
    	void run(){
    		int len=1;
    		for(int i=1;i<=n;++i){
    			int p=upper_bound(d+1,d+len+1,a[i],greater<int>())-d;//找到第一个小于a[i]的下标
    			dp[i]=p,d[p]=a[i];
    			if (p>len)
    				len=p;
    		}
    		int ans=0;
    		for(int i=1;i<=n;++i)
    			ans=max(ans,dp[i]);
    		printf("%d
    ",ans);
    	}
    }L1;
    struct LIS{
    	int dp[M],d[M],n;
    	void init(){n=cnt;}
    	void run(){
    		int len=0;
    		for(int i=1;i<=n;++i){
    			int p=lower_bound(d+1,d+len+1,a[i])-d;//找到第一个大于等于a[i]的下标
    			dp[i]=p,d[p]=a[i];
    			if (p>len)
    				len=p;
    		}
    		int ans=0;
    		for(int i=1;i<=n;++i)
    			ans=max(ans,dp[i]);
    		printf("%d
    ",ans);
    	}
    }L2;
    int main(){
    	int c;
    	while(~scanf("%d",&c))
    		a[++cnt]=c;
    	L1.init();
    	L2.init();
    	L1.run();
    	L2.run();
    	return 0;
    }
    
  • 相关阅读:
    Rust入坑指南:亡羊补牢
    antirez:Redis6真的来了
    代码检查又一利器:ArchUnit
    【译】浅谈SOLID原则
    Rust入坑指南:鳞次栉比
    【译】什么才是优秀的代码
    Elasticsearch从入门到放弃:文档CRUD要牢记
    【译】利用Lombok消除重复代码
    Netty 中的心跳检测机制
    Netty 中的异步编程 Future 和 Promise
  • 原文地址:https://www.cnblogs.com/diorvh/p/12078800.html
Copyright © 2020-2023  润新知