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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架