POJ - 2533 Longest Ordered Subsequence (最长单调子序列)

题意:
求所给出长度为 N 的最长上升子序列长度
""思路:**

(1) \(O(n^2)\)的 动态转移:
\(dp[i]\)表示以\(i\)结尾的最长单调子序列,那么当\(arr[i]>arr[j]时\) \(dp[i]=max(dp[j]+1,dp[i]) (j\in[1,i))\)

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(0); cin.tie(0);
#define accept 0
#define mp make_pair
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int inf = 0x3f3f3f3f;
const int maxn = 1e3+7;
const int maxm = 1e6+7;
const int mod = 1e9+7;

int dp[maxn];
int arr[maxn];
int main(){
    int n;
    while(~scanf("%d",&n)){
        for(int i=1;i<=n;i++){
            scanf("%d",&arr[i]);
            dp[i]  = 1;
        }
        
        int ans = -1;
        for(int i=1;i<=n;i++){
            for(int j=1;j<i;j++){
                if(arr[i]>arr[j]) dp[i] = max(dp[j]+1,dp[i]);
            }
            ans = max(ans,dp[i]);
        }
        printf("%d\n",ans);
    }
    return accept;
}

(2) \(O(n^2)\)
\(d[i] = 长度为i+1\)的递增子序列中末尾的最小值(不存在就是INF)
最开始用INF初始化dp数组的值,然后从前往后考虑数列的元素,对于每个\(a_j\),如果\(i\) 处于第一个位置 或者\(a[j] >= a[i],\)使得\(a[j] = a[i]\)并且\(break\),最后第一个dp数组中值为INF的下标即为结果
实际上很类似单调栈,将数组依次后移,如果遇到比前面dp小的就将其放在dp第一个比该值大的前一位(实现单调栈类似的效果),但是长度仍然按照最长计算。
因为要使得子序列最长,从贪心的角度来想如果该序列足够长,我们尽量使每个递增的差值最小,这样就能排更多的值。

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(0); cin.tie(0);
#define accept 0
#define mp make_pair
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int inf = 0x3f3f3f3f;
const int maxn = 1e3+7;
const int maxm = 1e6+7;
const int mod = 1e9+7;

int n;
int arr[maxn];
int dp[maxn];
int main() {
    int n;
    while(~scanf("%d",&n)){
        for(int i=1;i<=n;i++){
            scanf("%d",&arr[i]);
        }
        for(int i=1;i<=maxn;i++){
            dp[i] = inf;
        }
        dp[0] = 0;
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                if(i == 1|| dp[j] >= arr[i])  {
                    dp[j] = arr[i]; break;
                }
            }
        }
        int ans = 0;
        while(dp[ans] != inf) ans++;
        printf("%d\n", ans-1);
    }
    return 0;
}

(3)\(O(nlogn)\)
从第二种方法就能看出来,对于查找部分,我们不必要再遍历比较,可以使用二分进行优化

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(0); cin.tie(0);
#define accept 0
#define mp make_pair
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int inf = 0x3f3f3f3f;
const int maxn = 1e3+7;
const int maxm = 1e6+7;
const int mod = 1e9+7;

int n;
int arr[maxn];
int dp[maxn];
int main() {
    int n;
    while(~scanf("%d",&n)){
        for(int i=1;i<=n;i++){
            scanf("%d",&arr[i]);
            dp[i] = inf; 
        }
        dp[0] = 0;
        for(int i = 1; i <= n; i++) {
            *lower_bound(dp+1,dp+n+1,arr[i]) = arr[i];
        }
        int ans = lower_bound(dp+1,dp+1+n,inf) - dp;
        printf("%d\n", ans-1);
    }
    return 0;
}

转载于:https://www.cnblogs.com/Tianwell/p/11415894.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值