跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

HDU 6635 Nonsense Time 题解:逆向思维求解动态 LIS

HDU 6635 Nonsense Time 要求在线查询元素逐个激活后的最长上升子序列长度。常规正向动态维护困难,采用逆向思维,从所有元素激活状态开始逐步移除。基于数据随机性假设,平均时间复杂度可优化至 n*sqrt(n)*log(n)。核心逻辑是倒序遍历时检查被移除元素是否属于当前 LIS,若不属则长度不变,若属则需重新计算。实现采用贪心策略配合二分查找优化 LIS 更新过程。

女王发布于 2019/8/7更新于 2026/6/623 浏览
HDU 6635 Nonsense Time 题解:逆向思维求解动态 LIS

题目描述

You are given a permutation p1, p2, ..., pn of size n. Initially, all elements in p are frozen. There will be n stages that these elements will become available one by one. On stage i, the element p[ki] will become available.

For each i, find the longest increasing subsequence among available elements after the first i stages.

输入输出

Input

The first line of the input contains an integer T (1 ≤ T ≤ 3), denoting the number of test cases.

In each test case, there is one integer n (1 ≤ n ≤ 50000) in the first line, denoting the size of permutation.

In the second line, there are n distinct integers p1, p2, ..., pn (1 ≤ pi ≤ n), denoting the permutation.

In the third line, there are n distinct integers k1, k2, ..., kn (1 ≤ ki ≤ n), describing each stage.

It is guaranteed that p1, p2, ..., pn and k1, k2, ..., kn are generated randomly.

Output

For each test case, print a single line containing n integers, where the i-th integer denotes the length of the longest increasing subsequence among available elements after the first i stages.

解题思路

题目要求在元素逐个激活的过程中,每次查询当前可用元素的最长上升子序列(LIS)长度。正向动态维护较为困难,考虑采用逆向思维。

  1. 逆向处理:从所有元素都可用开始,逐步移除元素。倒序处理时,如果移除的元素不在当前的 LIS 中,则 LIS 长度不变;如果移除的元素在 LIS 中,则需要重新计算 LIS。
  2. 复杂度分析:最坏时间复杂度为 O(n^2 * log n),但由于数据是随机生成的,平均复杂度可优化至 O(n * sqrt(n) * log n)。
  3. 实现细节:使用贪心策略配合二分查找(lower_bound)来维护 LIS。记录每个数在 LIS 中的位置,以便判断被移除的数是否关键。

参考代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

typedef long long ll;
const int MAX = 1e6 + 10;
int a[MAX], b[MAX], c[MAX], pos[MAX], ans[MAX], d[MAX];
int cnt, w, sum, n;

void solve() {
    cnt = sum = 0;
    for (int i = 0; i <= n; i++) pos[i] = 0;
    for (int i = 1; i <= n; i++) {
        if (a[i] == 0) continue;
        if (cnt == 0 || a[i] > ans[cnt]) {
            ans[++cnt] = a[i];
            pos[i] = cnt;
        } else {
            int index = lower_bound(ans + 1, ans + cnt + 1, a[i]) - ans;
            ans[index] = a[i];
            pos[i] = index;
        }
    }
    w = cnt;
    int maxx = 5201314;
    sum = 0;
    for (int i = n; i >= 1; i--) {
        if (!cnt) break;
        if (pos[i] == cnt && maxx > a[i]) {
            cnt--;
            c[sum++] = a[i];
            maxx = a[i];
        }
    }
    sort(c, c + sum);
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for (int i = 1; i <= n; i++) scanf("%d", &b[i]);
        solve();
        for (int i = n; i >= 1; i--) {
            int index = lower_bound(c, c + sum, a[b[i]]) - c;
            if (c[index] != a[b[i]]) {
                d[i] = w;
                a[b[i]] = 0;
                continue;
            } else {
                d[i] = w;
                a[b[i]] = 0;
                solve();
            }
        }
        for (int i = 1; i <= n; i++) {
            if (i == 1) printf("%d", d[i]);
            else printf(" %d", d[i]);
        }
        puts("");
    }
    return 0;
}

总结

本题通过逆向思维将动态增加问题转化为动态删除问题,利用随机数据的特性降低了期望复杂度。核心在于快速判断被移除元素对 LIS 的影响,并适时更新状态。

目录

  1. 题目描述
  2. 输入输出
  3. Input
  4. Output
  5. 解题思路
  6. 参考代码
  7. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • C++ 类与对象基础详解(上)
  • 本地部署 Stable Diffusion 环境配置与避坑指南
  • 使用Selenium构建免费Web搜索API服务
  • C++ 继承机制详解:从基础到多继承与组合
  • C++ STL 竞赛常用容器详解
  • Promise.then() 链式调用核心原理与实战避坑指南
  • 合并 K 个升序链表
  • Visual C++ 运行库一体化解决方案
  • STL 有序关联容器详解:set、map 及其变体使用指南
  • Z-Image-Turbo Sugar 脸部 LoRA 模型部署与提示词指南
  • 基于 MCP 协议的 Claude 智能体天气服务落地示例
  • 算法基础:双指针法处理数组分块问题
  • Microsoft Edge WebView2 环境安装与故障排查指南
  • 医疗连续体机器人模块化控制界面设计与 Python 库应用
  • OpenClaw 技术解析:AI 代理的能力边界与潜在风险
  • Meta Quest VR 眼镜开机无法自动重连 WiFi 的解决方法
  • C++ 智能指针详解:RAII 原理与标准库实践
  • 基于 DeepFace 与 OpenCV 的实时情绪分析实战
  • LLM 工具调用统一 API 设计与实战
  • Virt A Mate (VAM) v1.22 中文汉化整合

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online