两道题目都牵扯到了一个问题,一个区间中存在的单调序列的个数
若要求序列单调不增,则序列个数为最长单调递增序列;(导弹拦截)
若要求序列单调不减,则个数为最长单调递减序列;(零件分组)
证明摘自某不知名blog:
对于某序列有增有减,则该序列所形成的严格单调递增序列必然为其每个互相完全不相同单调递减序列的某一个元素共同构成,即对于序列100 68 66 56 78 89 66 20 9,其严格单调递增序列为56 78 89。显然56,78,89永远为三个不同的递减序列中的元素。
假如严格单调递增序列的元素不为不同的递减序列的元素。即某个递减序列贡献了多个元素为严格单调递增序列元素,那么显然这多个元素是单调递增的,与递减序列矛盾。即可证明。
即:单增序列中的每个元素一定不处于同意单减序列中,反之亦然
导弹拦截:
#include<iostream>
#include<cstdio>
#include<algorithm>
#define INF 1061109567
using namespace std;
const int MAXN = 200000 + 50;
int n;
int A[MAXN],dp[MAXN],x;
int main()
{
while(cin >> x)A[++ n] = x;
for(int i = 1;i <= n;i ++)dp[i] = INF;
for(int i = 1;i <= n;i ++){
int loc = lower_bound(dp + 1,dp + n + 1,-A[i]) - dp;
dp[loc] = -A[i];
}
int ans1 = lower_bound(dp + 1,dp + n + 1,INF) - dp - 1;
for(int i = 1;i <= n;i ++){
dp[i] = INF;
}
for(int i = 1;i <= n;i ++){
int loc = lower_bound(dp + 1,dp + n + 1,A[i]) - dp;
dp[loc] = A[i];
}
int ans2 = lower_bound(dp + 1,dp + n + 1,INF) - dp - 1;
printf("%d\n%d",ans1,ans2);
return 0;
}
零件分组:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct edge
{
int w,l;
}l[100010];
int n;
bool cmp(edge a,edge b)
{
return a.w <= b.w;
}
int L[100010];
int dp[100010];
int main()
{
scanf("%d",&n);
for(int i = 1;i <= n;i ++)
{
scanf("%d%d",&l[i].w,&l[i].l);
}
sort(l + 1,l + n + 1,cmp);
for(int i = 1;i <= n;i ++)L[i] = -l[i].l,dp[i] = 1061109567;
for(int i = 1;i <= n;i ++)
{
int loc = lower_bound(dp + 1,dp + n + 1,L[i]) - dp;
dp[loc] = L[i];
}
int ans = lower_bound(dp + 1,dp + n + 1,1061109567) - dp;
printf("%d",ans - 1);
return 0;
}

本文介绍了如何使用最长单调子序列算法解决两类问题:求解区间内的单调递减序列数量(如导弹拦截问题)和单调递增序列数量(如零件分组问题)。文中通过一个实例解释了单调递增序列与单调递减序列之间的关系,并提供了两个C++实现示例。
9530

被折叠的 条评论
为什么被折叠?



