dp - LIS

  1. 设计状态 d p [ i ] dp[i] dp[i] 表示 以 a [ i ] a[i] a[i] 为结尾的最长上升子序列的长度

  2. 找初始状态dp[i] = 1;

  3. 转移方程

    1. 一个以 a [ i ] a[i] a[i] 为单独元素的序列 dp[i] = 1;

    2. 存在 j < i j<i j<ia[j]<a[i]; dp[i] = max(dp[j]) + 1;

  4. 答案ans = max(dp[i]);

for(i=1; i<=n; ++i) { // O(n^2) 
	dp[i] = 1;
	for(int j=1; j<i; ++j) {
		if(a[j] < a[i])
			dp[i] = max(dp[i], dp[j]+1);
	}
}

for(int i=1; i<=n; ++i)
	ans = max(ans, dp[i]);
  1. 设计状态 d p [ i ] dp[i] dp[i] 表示 长度为 i i i的上升子序列末尾元素的最小值

  2. 初始状态dp[i] = INF; dp[1] = a[1];

  3. 转移方程if(j>i && dp[i] >= a[j]) dp[i] = a[j];

  4. 答案ans = min(i) && dp[i]!=INF;

dp数组一定是单调递增的

for(int i=1; i<=n+1; ++i) {
	dp[i] = INF;
}

dp[1] = a[1];

for(int i=2; i<=n; ++i) {  // 枚举a数组 
	for(int j=1; j<=n; ++j) { // 枚举dp数组, 每次找一个大于等于 a[i] 的位置 
		if(dp[j] >= a[i]) {
			dp[j] = a[i];
			break;
		} 
	} 
}

for(int i=2; i<=n; ++i) {
	*lower_bound(dp+1, dp+n+1, a[i]) = a[i];
} 
int ans = lower_bound(dp+1, dp+n+2, INF) - (dp+1);  

printf("%d\n", ans);

原理: 二分

1. lower_bound(l, r+1, x)表示在 区间 [ l , r ] [l, r] [l,r]中找到第一个 > = x >= x >=x 的位置 (指针)
2. upper_bound(l, r+1, x)区间 [ l , r ] [l, r] [l,r]中找到第一个 > x > x >x 的位置 (指针)
3. 前面加上星号就是具体的值 *lower_bound(l, r+1, x)
int ans = 0;
for(int i=; i<=n; ++i) {
	if(dp[i]==INF) {
		ans = i-1;
		break; 
	} 
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值