bzoj 4553: [Tjoi2016&Heoi2016]序列
Description
佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他。玩具上有一个数列,数列中某些项的值
Input
输入的第一行有两个正整数n, m,分别表示序列的长度和变化的个数。接下来一行有n个数,表示这个数列原始的
Output
输出一个整数,表示对应的答案
Sample Input
1 2 3
1 2
2 3
2 1
3 4
Sample Output
HINT
Source
易得方程:
dp[i]=max{dp[j]+1}(j<i&&MAX[j]<=a[i]&&a[j]<=MIN[i])
然后我们发现这是一个三维偏序问题,可以使用CDQ+树状数组来进行优化。。。
设dp[i]表示以i号结尾的最长不下降子序列的长度,对于分治区间 𝑙, 𝑟 ,我们先递归处理编号上的左半部分
[𝑙, 𝑚𝑖𝑑],然后用左半部分更新右半部分。这样的更新方式,保证了左半部分更新右半部分时左半部分解的
最优性(因为右半部分不会对其迚行更新(即满足𝑖 ≥ 𝑗))。对于当前处理的区间,使用归并+树状数组进行更
新。
然而我一下就被lst大佬问得怀疑人生。。。仔细琢磨了一下,大致是这样的。。。
首先在外面把a排序。。。
然后solve(l,r)的操作:
1.把[l,r]按照序号分为两个部分(j<i这一维就解决了)
2.solve(l,mid),递归处理左边,处理完之后左边变为按照MAX增序,右边仍然是按照a排序。。。(这样MAX[j]<=a[i]这一维就解决来)
3.用左边区间[l,mid]的dp值来更新右边[mid+1,r]的dp值,具体做法就是把(a[j]<=MIN[i])这一维丢进树状数组,然后查询。。。
4.solve(mid+1,r),递归处理[mid+1,r];
5.按照MAX归并[l,r]。。。
感觉CDQ一直学得云里雾里放光彩。。。GG。。。这个题真的是细思极恐。。。我可能学了一个假的CDQ。。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | // MADE BY QT666 #include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #include<cstring> using namespace std; typedef long long ll; const int N=100050; struct data{ int a,Min,Max,id,dp; }g[N],q[N]; bool cmp( const data &a, const data &b){ return a.a<b.a;} int n,m,tr[N],T=1e5; void update( int x, int val){ for ( int i=x;i<=T;i+=i&-i) tr[i]=max(tr[i],val); } void del( int x){ for ( int i=x;i<=T;i+=i&-i) tr[i]=0; } int query( int x){ int ret=0; for ( int i=x;i;i-=i&-i) ret=max(ret,tr[i]); return ret; } void CDQ( int l, int r){ if (l==r){g[l].dp=max(g[l].dp,1); return ;} int mid=(l+r)>>1; int tt=l-1,sum=mid; for ( int i=l;i<=r;i++){ if (g[i].id<=mid) q[++tt]=g[i]; else q[++sum]=g[i]; } for ( int i=l;i<=r;i++) g[i]=q[i];CDQ(l,mid); for ( int i=mid+1,x=l;i<=r;i++){ for (;g[x].Max<=g[i].a&&x<=mid;x++) update(g[x].a,g[x].dp); g[i].dp=max(g[i].dp,query(g[i].Min)+1); } for ( int i=l;i<=mid;i++) del(g[i].a); CDQ(mid+1,r);tt=l,sum=mid+1; for ( int i=l;i<=r;i++){ if ((g[tt].Max<=g[sum].Max&&tt<=mid)||(g[tt].Max>g[sum].Max&&sum>r)) q[i]=g[tt++]; else q[i]=g[sum++]; } for ( int i=l;i<=r;i++) g[i]=q[i]; } int main(){ scanf( "%d%d" ,&n,&m); int x,y,ans=0; for ( int i=1;i<=n;i++) scanf( "%d" ,&g[i].a),g[i].Min=g[i].a,g[i].Max=g[i].a,g[i].id=i; for ( int i=1;i<=m;i++) scanf( "%d%d" ,&x,&y),g[x].Min=min(g[x].Min,y),g[x].Max=max(g[x].Max,y); sort(g+1,g+1+n,cmp);CDQ(1,n); for ( int i=1;i<=n;i++) ans=max(ans,g[i].dp); printf( "%d\n" ,ans); return 0; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App