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

UVa 1471 Defense Lines

题目描述

在最后一次战争摧毁了你的国家之后,作为阿德尼亚王国的国王,你决定是时候加强首都的防御了。你的防御工事的一部分是一排法师塔,从城市附近开始一直延伸到北部森林。你的顾问们确定防御质量只取决于一个因素:最长的连续递增塔高序列的长度

经过一些艰难的谈判,建造新塔已经不可能了。不过,阿德尼亚的法师们同意拆除一些塔。你可以拆除任意数量的塔,但法师们提出了一个条件:这些塔必须是连续的

例如,如果塔的高度分别是 5,3,4,9,2,8,6,7,15, 3, 4, 9, 2, 8, 6, 7, 15,3,4,9,2,8,6,7,1,那么通过拆除高度为 9,2,89, 2, 89,2,8 的塔,最长的连续递增塔序列是 3,4,6,73, 4, 6, 73,4,6,7

题目分析

问题理解

我们需要在删除一段连续塔楼后,找到剩余塔楼序列中最长的连续递增子序列的长度。关键约束是:

  • 只能删除一段连续的塔楼(可以不删除)
  • 删除后剩下的塔楼保持原来的相对顺序
  • 需要找到最长的连续递增子序列

输入输出规格

  • 输入:多个测试用例,第一行是测试用例数量 Z≤25Z \leq 25Z25,每个测试用例包含塔的数量 n≤2×105n \leq 2 \times 10^5n2×105 和塔的高度序列
  • 输出:每个测试用例输出一个整数,表示通过删除一段连续塔楼后能得到的最长连续递增序列的长度

解题思路

关键观察

  1. 基础情况:如果不删除任何塔楼,答案就是原序列的最长连续递增子序列长度
  2. 连接两个递增序列:通过删除中间的一段塔楼,我们可以将两个递增序列连接起来,条件是前一个序列的最后一个元素小于后一个序列的第一个元素

算法设计

步骤1:预处理数组

定义两个辅助数组:

  • f[i]f[i]f[i]:以第 iii 个塔结尾的最长连续递增子序列长度
  • g[i]g[i]g[i]:以第 iii 个塔开头的最长连续递增子序列长度

计算方式:

  • f[0]=1f[0] = 1f[0]=1,对于 i>0i > 0i>0:如果 a[i]>a[i−1]a[i] > a[i-1]a[i]>a[i1],则 f[i]=f[i−1]+1f[i] = f[i-1] + 1f[i]=f[i1]+1,否则 f[i]=1f[i] = 1f[i]=1
  • g[n−1]=1g[n-1] = 1g[n1]=1,对于 i<n−1i < n-1i<n1:如果 a[i]<a[i+1]a[i] < a[i+1]a[i]<a[i+1],则 g[i]=g[i+1]+1g[i] = g[i+1] + 1g[i]=g[i+1]+1,否则 g[i]=1g[i] = 1g[i]=1
步骤2:考虑三种情况
  1. 不删除任何塔楼:答案为 max⁡(f[i])\max(f[i])max(f[i])
  2. 删除单个塔楼:对于位置 iii,如果 a[i]<a[i+2]a[i] < a[i+2]a[i]<a[i+2],可以连接 f[i]f[i]f[i]g[i+2]g[i+2]g[i+2]
  3. 使用数据结构优化查找:对于每个位置 iii,找到 j<ij < ij<i 使得 a[j]<a[i]a[j] < a[i]a[j]<a[i]f[j]f[j]f[j] 最大
步骤3:使用 set\texttt{set}set 维护候选解

维护一个 set\texttt{set}set,其中存储 (a[j],f[j])(a[j], f[j])(a[j],f[j]) 对,并保证:

  • 随着 a[j]a[j]a[j] 增加,f[j]f[j]f[j] 也严格增加
  • 这样可以快速二分查找满足 a[j]<a[i]a[j] < a[i]a[j]<a[i] 的最大 f[j]f[j]f[j]

算法复杂度

  • 时间复杂度O(nlog⁡n)O(n \log n)O(nlogn),主要来自 set\texttt{set}set 操作
  • 空间复杂度O(n)O(n)O(n),用于存储 fffggg 数组

代码实现

// Defense Lines
// UVa ID: 1471
// Verdict: Accepted
// Submission Date: 2025-10-19
// UVa Run Time: 0.440s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net#include <bits/stdc++.h>
using namespace std;const int MAXN = 200005;int a[MAXN], f[MAXN], g[MAXN];int main() {int Z;scanf("%d", &Z);while (Z--) {int n;scanf("%d", &n);for (int i = 0; i < n; i++) {scanf("%d", &a[i]);}// 计算f[i]: 以i结尾的最长连续递增子序列长度f[0] = 1;for (int i = 1; i < n; i++) {if (a[i] > a[i-1]) f[i] = f[i-1] + 1;else f[i] = 1;}// 计算g[i]: 以i开头的最长连续递增子序列长度g[n-1] = 1;for (int i = n-2; i >= 0; i--) {if (a[i] < a[i+1]) g[i] = g[i+1] + 1;else g[i] = 1;}int ans = 0;// 情况1: 不删除任何塔楼for (int i = 0; i < n; i++) {ans = max(ans, f[i]);}// 情况2: 删除单个塔楼for (int i = 0; i < n - 2; i++) {if (a[i] < a[i+2]) {ans = max(ans, f[i] + g[i+2]);}}// 情况3: 使用set优化查找set<pair<int, int>> s; // 存储(a[j], f[j])对for (int i = 0; i < n; i++) {if (i > 0) {// 在set中查找满足a[j] < a[i]的最大f[j]auto it = s.lower_bound({a[i], -1});if (it != s.begin()) {it--;ans = max(ans, it->second + g[i]);}}// 维护set,删除被支配的元素auto it = s.lower_bound({a[i], -1});bool should_insert = true;// 如果存在相同a值但f值更大的元素,不插入当前元素if (it != s.end() && it->first == a[i]) {if (it->second >= f[i]) {should_insert = false;} else {s.erase(it);}}if (should_insert) {// 插入当前元素it = s.insert({a[i], f[i]}).first;// 检查前一个元素,如果前一个元素的f值更大,删除当前元素if (it != s.begin()) {auto prev_it = it;prev_it--;if (prev_it->second >= it->second) {s.erase(it);should_insert = false;}}// 删除后面被当前元素支配的元素if (should_insert) {auto next_it = it;next_it++;while (next_it != s.end() && next_it->second <= it->second) {next_it = s.erase(next_it);}}}}printf("%d\n", ans);}return 0;
}

总结

本题的关键在于理解如何通过删除一段连续塔楼来连接两个递增序列,并使用高效的数据结构来优化查找过程。通过预处理 fffggg 数组,我们可以快速计算基础情况,然后使用set来维护候选解集合,确保在 O(nlog⁡n)O(n \log n)O(nlogn) 时间内解决问题。

http://www.dtcms.com/a/503401.html

相关文章:

  • 【题解】洛谷 P11673 [USACO25JAN] Median Heap G [树形 dp]
  • 气球游戏(DP,分治)
  • MySQL同步连接池与TrinityCore的对比学习(六)
  • UserWarning: No file found at “C:\Faces\image_0032.jpg“AssertionError
  • 网站生成器下载wordpress 添加微博关注
  • 【个人成长笔记】Qt Creator快捷键终极指南:从入门到精通
  • 【开题答辩过程】以《校园可共享物品租赁系统的设计与实现》为例,不会开题答辩的可以进来看看
  • 北京高端网站定制公司猎头公司工作怎么样
  • StarRocks-基本介绍(一)基本概念、特点、适用场景
  • Java零基础入门:从封装到构造方法 --- OOP(上)
  • JAVA算法练习题day43
  • 如何学习Lodash源码?
  • 建个自己的网站难吗宁波 seo整体优化
  • uni-app详解
  • AI学习:SPIN -win-安装SPIN-工具过程 SPIN win 电脑安装=accoda 环境-第五篇:代码修复]
  • 【Linux】Linux:sudo 白名单配置与 GCC/G++ 编译器使用指南
  • PyTorch 张量初始化方法详解
  • 计算机理论学习Day16
  • 动物摄影网站佛山网站制作维护
  • springboot整合redis-RedisTemplate单机模式
  • 【Redisson】分布式锁原理和使用姿势
  • linux学习笔记(43)网络编程——HTTPS (补充)
  • HTTP Client/Server 理论
  • 怎么申请域名建立网站宁波网站建设开发
  • C++:内存管理 |内存分布|回顾|new/delete底层|实现原理|拓展|定位new|池化技术|总结区别对比
  • 上街网站建设做语文高考题网站
  • 前端基础二、CSS(一)、CSS基础知识
  • 【MySQL】第三章 运算符
  • 智能机器人梯控系统(含二维码/刷卡/人脸识别)安装布线指南,结合工程规范与安全要点进行结构化优化,内容清晰、可操作性强
  • 突破 @Valid 局限!Spring Boot 编程式验证深度解析与复杂场景实战