木棍加工——线性dp、dilworth定理、最长上升子序列
P1233 木棍加工 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
读题可知我们要求的是将所有木棍分割成长度与宽度都是不上升子序列的序列个数。
既然是不上升子序列,那么我们就结构体排序一下。
1 bool cmp(const node&s1,const node&s2) 2 { 3 if(s1.l==s2.l)return s1.w>s2.w; 4 return s1.l>s2.l; 5 }
根据dilworth定理:
一个序列要最少分割为多少个不上升子序列的个数等于该序列最长上升子序列的长度。
注意:虽然问题转化为求最长上升子序列,但是该序列仍应该是排好序的原本序列,而不是再将序列排成从小到大上升的序列进行求值。是在原序列基础上求的长度!!
那么问题就转化为求该序列的最长上升子序列的长度。
方法1:O(n^2)
状态表示:排序后以第i个数字为终点的最长上升子序列的长度
状态计算:j从1到i-1遍历一遍,如果符合上升的要求(j的宽度小于i的宽度)那就f[i]=max(f[j]+1,f[i])。
如果不符合上升的要求,那就continue
问题:为什么符合上升的要求只需要考虑宽度,不考虑长度呢?
回答:因为咱们总序列的排序就是按照长度由大到小排的,相当于把长度这一维给看作定值,通过求宽度由小到大的最长上升子序列长度来得到答案(这是由dilworth定理推出来的)。

1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N=5e3+100; 4 struct node 5 { 6 int l,w; 7 }e[N]; 8 int f[N]; 9 bool cmp(const node&s1,const node&s2) 10 { 11 if(s1.l==s2.l)return s1.w>s2.w; 12 return s1.l>s2.l; 13 } 14 int main() 15 { 16 int n;scanf("%d",&n); 17 for(int i=1;i<=n;i++)scanf("%d%d",&e[i].l,&e[i].w); 18 sort(e+1,e+1+n,cmp); 19 20 int ans=0; 21 for(int i=1;i<=n;i++) 22 { 23 f[i]=1; 24 for(int j=1;j<i;j++) 25 { 26 if(e[j].w<e[i].w&&f[i]<f[j]+1) 27 f[i]=f[j]+1; 28 } 29 ans=max(ans,f[i]); 30 } 31 32 printf("%d\n",ans); 33 34 35 return 0; 36 }
方法2:O(nlogn)
状态表示:排序后以第i个数字为终点的上升子序列结尾的最小值。
状态计算:用i将序列遍历一遍,如果第i个结构体的宽度大于f[ans],那么f[++ans]=第i个结构体的宽度。
否则,就二分求大于等于第i个结构体宽度的最小的那个位置k,f[k]=第i个结构体的宽度。
最后答案求的是最长上升子序列的长度,也就是ans的大小啦。

1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N=5e3+100; 4 int f[N],ans; 5 struct node 6 { 7 int l,w; 8 }e[N]; 9 10 bool cmp(const node&s1,const node&s2) 11 { 12 if(s1.l==s2.l)return s1.w>s2.w; 13 return s1.l>s2.l; 14 } 15 16 int main() 17 { 18 int n;scanf("%d",&n); 19 for(int i=1;i<=n;i++)scanf("%d%d",&e[i].l,&e[i].w); 20 21 sort(e+1,e+1+n,cmp); 22 for(int i=1;i<=n;i++) 23 { 24 if(e[i].w>f[ans])f[++ans]=e[i].w; 25 else 26 { 27 int k=lower_bound(f+1,f+1+ans,e[i].w)-f; 28 f[k]=e[i].w; 29 } 30 } 31 32 printf("%d\n",ans); 33 34 return 0; 35 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现