当前位置: 首页 > news >正文

P8277 [USACO22OPEN] Up Down Subsequence P 题解

P8277 [USACO22OPEN] Up Down Subsequence P 题解

题目传送门。

给一种码量有点大,但是思维难度不大的线段树优化 dp 做法。

一开始想了好久二分答案然后 check 的思路……

题意很简单,不说了。考虑 dp。

\(f_{i,0/1}\) 表示以 \(i\) 结尾,取出来后对应的字符为 UD 的选取最大值。

转移:

更新 U:需要保证 \(j<i\) 并且 \(f_{j,0/1}\) 对应的字符是 U。因为我们正在更新 U

同理,更新 D 需要保证 \(j>i\)\(f_{j,0/1}\) 对应的字符是 D

所以我们就得到了 \(O(n^2)\) 的部分分程序:

#include<bits/stdc++.h>
using namespace std;
typedef long long ljl;
const int N=3e5+5;
int n,f[N][2],a[N],ans;
string s;
int main(){ios::sync_with_stdio(0);cin>>n;for(int i=1;i<=n;++i)cin>>a[i];cin>>s;s=" "+s;for(int i=1;i<=n;++i){int x=a[i];f[x][0]=f[x][1]=1;for(int j=1;j<i;++j){int y=a[j];if(y<x){if(s[f[y][0]]=='U')f[x][0]=max(f[x][0],f[y][0]+1);if(s[f[y][1]]=='U')f[x][0]=max(f[x][0],f[y][1]+1);}if(y>x){if(s[f[y][0]]=='D')f[x][1]=max(f[x][1],f[y][0]+1);if(s[f[y][1]]=='D')f[x][1]=max(f[x][1],f[y][1]+1);}}ans=max(ans,max(f[x][0],f[x][1]));}
//	for(int i=1;i<=n;++i)
//	{
//		cout<<i<<": ";
//		cout<<f[i][0]<<' '<<f[i][1]<<'\n';
//	}cout<<ans-1<<'\n';return 0;
}

然后考虑优化。

注意到每次查询,要么是 \([1,x-1]\),要么是 \([x+1,n]\),是一段连续的区间。

所以可以考虑用线段树维护最大值。

具体地,为 UD 各开一个线段树。编号还是 \(0\) 对应 U\(1\) 对应 D

然后每次转移就只要 query 一下线段树就可以了,单次时间复杂度 \(O(\log n)\)

最后考虑更新线段树。

首先线段树编号对应 \(0\)\(1\)

然后就是把 \(f_{i,0/1}\) 插入线段树 \(i\) 号位。

注意有可能 \(f_{i,0}\)\(f_{i,1}\) 都插进了 \(i\) 号位,所以线段树更新的时候要 node[p][i].maxn=max(val,node[p][i].maxn);,而不是 node[p][i].maxn=val;

总时间复杂度 \(O(n\log n)\)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ljl;
const int N=3e5+5;
int lowbit(int x){return x&(-x);}
int n,f[N][2],a[N],ans,maxu,maxd;
string s;
struct NODE{int l,r,maxn;
}node[N*4][2];
#define lc (p<<1)
#define rc (p<<1|1)
void pushup(int p,int i)
{if(node[p][i].l==node[p][i].r)return;node[p][i].maxn=max(node[lc][i].maxn,node[rc][i].maxn);return;
}
void bld(int l,int r,int p,int i)
{node[p][i].l=l;node[p][i].r=r;if(l==r)return;int mid=(node[p][i].l+node[p][i].r)/2;bld(l,mid,lc,i);bld(mid+1,r,rc,i);pushup(p,i);return;
}
void addx(int x,int val,int p,int i)
{
//	cout<<node[p][i].l<<' '<<node[p][i].r<<'\n';if(node[p][i].l==node[p][i].r){node[p][i].maxn=max(val,node[p][i].maxn);return; }int mid=(node[p][i].l+node[p][i].r)/2;if(x<=mid)addx(x,val,lc,i);elseaddx(x,val,rc,i);pushup(p,i);return;
}
int query(int l,int r,int p,int i)
{if(l<=node[p][i].l&&node[p][i].r<=r)return node[p][i].maxn;int mid=(node[p][i].l+node[p][i].r)/2,ans=0;if(l<=mid)ans=max(ans,query(l,r,lc,i));if(mid<r)ans=max(ans,query(l,r,rc,i));return ans;
}
int main(){ios::sync_with_stdio(0);cin>>n;for(int i=1;i<=n;++i)cin>>a[i];cin>>s;s=" "+s;bld(1,n,1,0);bld(1,n,1,1);for(int i=1;i<=n;++i){int x=a[i];f[x][0]=f[x][1]=1;f[x][0]=max(f[x][0],query(1,x-1,1,0)+1);f[x][1]=max(f[x][1],query(x+1,n,1,1)+1);ans=max(ans,max(f[x][0],f[x][1]));if(s[f[x][0]]=='U')addx(x,f[x][0],1,0);if(s[f[x][1]]=='U')addx(x,f[x][1],1,0);if(s[f[x][0]]=='D')addx(x,f[x][0],1,1);if(s[f[x][1]]=='D')addx(x,f[x][1],1,1);}
//	for(int i=1;i<=n;++i)
//	{
//		cout<<i<<": ";
//		cout<<f[i][0]<<' '<<f[i][1]<<'\n';
//	}cout<<ans-1<<'\n';return 0;
}

你说得对,但是本来想用树状数组的,但是发现好像不太容易用 \([1,r]\) 的答案减去 \([1,l-1]\) 的答案,于是用了线段树。虽然常数大了点,但好歹思维难度不高。

UPD:写完后想了想,发现其实可以用树状数组。因为只有 \([x+1,n]\) 这类型的区间,所以可以反着再建树状数组,反着查询。不过这太麻烦了。

http://www.jsqmd.com/news/412599/

相关文章:

  • Colo 环境服务器的操作指南
  • LuatOS核心库API——【json 】json 生成和解析库
  • SRE 应用稳定性看板-从应用健康/业务系统维度的评分系统
  • AI辅助企业战略制定:竞争态势分析与机会识别
  • AI论文工具排行榜:十大写作与文本重构解决方案详解
  • 论文写作利器:9款自动目录生成工具详解及实时更新功能。
  • 基于STM32实现OTABootLoader 第三章——构建BootLoader程序
  • Storm监控与运维:保障大数据处理系统稳定运行
  • 智能写作领域Top10:多维度解析AI文本改写工具的核心优势
  • AIGC论文助手权威榜单:十大AI文本优化工具全面解析
  • 提示工程架构师解读:提示工程如何优化用户培养
  • 大数据领域Kafka的网络拓扑优化
  • 华为OD机考双机位C卷 - 根据IP查找城市(Java Python JS GO C++ C)
  • MAC地址硬刷工具|修改网卡物理地址,BIOS级写入,重装系统不还原
  • OKX 客户 Colo 内网域名接入方式
  • seedance 2.0牛在哪里?
  • 基于深度学习的违章停车检测系统的设计与实现
  • 如何看待OpenClaw(曾用名:Clawdbot、Moltbot)?
  • C++/Python混合编程之Pybind11的使用
  • SRE 应用稳定性看板-从应用维度监控服务健康状态,基于 Apdex 评分体系
  • 大数据领域数据中台的质量评估方法
  • 使用 Terraform + Terragrunt 管理 AWS 基础设施项目说明
  • **4皇后问题回溯搜索过程**的图文解析、关键函数说明及核心考点总结,结构清晰、逻辑准确
  • 系统思考:自由职业背后的悖论
  • Sora2 免费去水印网站
  • **回溯法在两个经典问题(0-1背包、n皇后)中的应用**的清晰解读,涵盖了搜索树结构、剪枝策略、可行解识别与核心约束条件
  • Learning on the Manifold: Unlocking Standard Diffusion Transformers withRepresentation Encoders
  • **分支限界法(结合回溯思想)求解0-1背包问题**的核心流程与结果
  • 20260225 之所思 - 人生如梦
  • build_fsd_luyan_from_rm——注释