专栏文章

题解:P8776 [蓝桥杯 2022 省 A] 最长不下降子序列

P8776题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mipqwxod
此快照首次捕获于
2025/12/03 16:29
3 个月前
此快照最后确认于
2025/12/03 16:29
3 个月前
查看原文
前置芝士:树状数组(不清楚的去问问度娘)。
题目大意:求修改 kk 个数之后的最长不下降子序列。
思路:用 dpidp_i 表示从第 11 个到第 ii 个数的最长不下降子序列,用 pdipd_i 表示从第 11 个数到第 nn 个数的最长不下降子序列,要维护一个区间的最大值可以用什么?没错就是树状数组,用树状数组维护当前区间的最长不下降子序列,因为可以修改连续的 kk 个数。所以我们可以利用这 kk 个数让 dpidp_ipdipd_i 连接起来。不清楚的可以看看图片,我们可以得出结果是 max(dpi+k+pdi1,ans)\max(dp_i+k+pd_i-1,ans)
如图:
(有点抽象但是已经认真画了)
代码如下:
CPP
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,a[N],k,dp[N],pd[N],t[N],ans=0;
int lowbit(int x)//树状数组 
{
	return x&(-x);//lowbit不过多解释不知道的可以去度娘看看 
}
void up(int x,int v);//维护x节点的最大值 修改x的值 
int q(int x);//维护最长不下降子序列 
signed main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		dp[i]=1;
		pd[i]=1;//初始化 
	}
	for(int i=0;i<N;i++)t[i]=1;
	dp[1]=1;
	pd[n]=1;
	for(int i=2;i<=n;i++)//求从1到i的最长不下降子序列 
	{
		dp[i]=q(a[i]);//找前缀最大值 
		up(a[i],dp[i]+1);//更新树状数组 
	} 

	for(int i=0;i<N;i++)t[i]=1;//初始化 
	for(int i=n-1;i>=1;i--)//求从i到n的最长不下降子序列 
	{
		pd[i]=q(N-a[i]);//因为要从右向左找 但是树状数组的逻辑默认是从小到大维护值的所以要取反 
		up(N-a[i],pd[i]+1);//更新树状数组 
	}
	for(int i=1;i<=n;i++)
	{
		ans=max(ans,dp[i]+k+pd[i]-1);//枚举节点找最优 
	}
	cout<<min(ans,n)<<"\n";
	return 0;
}
int q(int x)//
{
	int ans=0;//初始化最大值为0 
	while(x>0)//从x开始向下遍历 
	{
		ans=max(ans,t[x]);//更新当前区间的最大值 
		x-=lowbit(x);//移动到左边的节点 
	}
	return ans;
}
void up(int x,int v)//维护x节点的最大值 
{
	while(x<=N)//从位置x开始,向上更新树状数组
	{
		t[x]=max(t[x],v);// 更新当前节点为最大值
		x+=lowbit(x);// 移动到父节点 
	}
	return ;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...