2/9 P1020 最长不上升子序列

又是新芝士!
放个链接先:https://www.luogu.com.cn/problem/P1020

做的时候(×)抄的时候(√)一直不懂为什么替换掉元素不会有影响,为什么len不用变,后面怎么改变len的值来着,真是太逊了呜呜

在deepseek的支持下得到了理解(以最长不上升子序列为例):

当一个数比当前的数大时,就把它替换到

dp [ upper_bound (dp+1 , dp+1+len , a[i] , greater<>( ) ) -dp ] greater<>()是为了把找到更大的变为找到更小的!

这时候末尾元素不变,len不变,我们要的就是这个效果!

因为我们不知道这个数 带来的新的可能性 会不会比当前的长,所以先放在那里

当我们不断往下找的时候,其他新的可能性也会不断加入到前面

最终有可能新的可能性追上了当前的长度len,这时候len同时记录新旧,下一个自然会过渡到更有优势的那一个可能性啦~

用DS的话来解释就是:
维护一个尽可能“有潜力”的序列(末尾元素尽量小/大),方便后续元素扩展
替换不影响最终长度:替换操作只优化后续扩展的可能性,不改变已计算的序列长度上限。

另外,upper_bound/lower_bound 是二分查找,会比较快!(其实就是不会自己写二分×)

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long int LL;
LL n,h[100010],dp1[100010],dp2[100010],len1,len2;

int main()
{
	while(scanf("%d",&h[++n])!=EOF);
	n--,len1=1,len2=1;
	dp1[1]=h[1],dp2[1]=h[1];
	for(LL i=2;i<=n;i++)
	{
		if(h[i]<=dp1[len1])
		{
			dp1[++len1]=h[i];
		}
		else
		{
			LL re=upper_bound(dp1+1,dp1+1+len1,h[i],greater<LL>())-dp1;
			dp1[re]=h[i];
		}
		if(h[i]>dp2[len2])
		{
			dp2[++len2]=h[i];
		}
		else
		{
			LL re=lower_bound(dp2+1,dp2+1+len2,h[i])-dp2;
			dp2[re]=h[i];
		}
	}
	
	cout<<len1<<endl<<len2;
	return 0;
}

posted @   石磨豆浆  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示