leetcode 第133场双周赛 100333.统计逆序对的数目【计数dp/滚动数组/前缀和优化】

news2025/1/18 7:00:36

在这里插入图片描述
分析:
先考虑如下问题。

求长度为n,逆序对为m的排列数量。

可以考虑dpdp[i][j]定义为长度为i,逆序对为j的排列数量。

dp[1][0] = 1;
//枚举排列长度,或者认为枚举当前需要插到长度为i-1的排列中的数字
for(int i = 1; i <= n; ++i)  
{
    for(int j = 0; j <= i * (i + 1) / 2; ++j)
    {
        //枚举当前数字插到的位置,一共i个位置,分别可能使逆序对增加0~i-1个
        for(int k = 0; k < i; ++k)
        {
            if(j >= k)
            {
                dp[i][j] += dp[i - 1][j - k];
            }
        }
    }
}

在懂了上述dp之后,再来考虑本题。主要有两个问题。

  • 另外考虑,如果dp[i][j]是否依旧可以这样求,因为上述问题中对于长度为i的排列,前i-1个数字确定的,i一定是最大的,我们只需要考虑它放在哪个位置即可。
  • 如何同时满足requirements[i][endi] = cntirequirements[j][endj] = cntj,其中i!=j

对于第一点,肯定是可以这样求的,一方面我们不需要关心前i-1个数字是什么,只需要认为我们枚举的第i个数字是这i个数字中最大的(类似上述思路)或者是最小的(与最大的等效并且更加方便理解上述dp的最内层循环)即可,另一方面我们看到至少有一个i满足endi == n - 1

对于第二点,我们只需要在dp的过程中适当修改。若 ∃ e n d j = = i \exists end_j == i endj==i,则正常求 d p [ i ] [ c n t j ] dp[i][cnt_j] dp[i][cntj]的值,而 d p [ i ] [ k ] = 0 , k ≠ c n t j dp[i][k]=0,k\ne cnt_j dp[i][k]=0,k=cntj

AC代码

class Solution {
public:
    int numberOfPermutations(int n, vector<vector<int>>& requirements) {
        
        const int mod = 1e9 + 7;
        
        vector<int> vt(305, -1);
        for(auto x: requirements) vt[x[0] + 1] = x[1];

        vector<vector<int>> dp(305, vector<int>(405, 0));
        dp[0][0] = 1;

        for (int i = 1; i <= n; ++i) 
        {
            if (vt[i] != -1) 
            {
                int j = vt[i];
                for (int k = 0; k < i; ++k) if (j >= k) dp[i][j] = (dp[i][j] + dp[i - 1][j - k]) % mod;
                continue;
            }
            for (int j = 0; j <= min(400, (1 + i) * i / 2); ++j) 
            {
                for (int k = 0; k < i; ++k) 
                {
                    if (j >= k) dp[i][j] = (dp[i][j] + dp[i - 1][j - k]) % mod;
                }
            }
        }
        
        return dp[n][vt[n]];
    }
};
//dp数组定义为vector,如果定义为数组,一定记得先memset 0
//(dp[i][j] += dp[i - 1][j - k]) % mod不等价于dp[i][j] = (dp[i][j] + dp[i - 1][j - k]) % mod;
//(dp[i][j] += dp[i - 1][j - k]) % mod,模完之后值未赋给任何数。

上述代码已经可以AC,但是可以进一步优化

  • dp[i][j]的递推过程中,只用到了dp[i-1][j-k],故可以通过滚动数组优化空间。
  • 对于最内层枚举k的循环,我们发现递推公式等价于 d p [ i ] [ j ] = ∑ k = j − ( i − 1 ) j d p [ i − 1 ] [ k ] dp[i][j] = \sum_{k=j-(i-1)}^{j} dp[i-1][k] dp[i][j]=k=j(i1)jdp[i1][k],即是dp[i-1]数组的一个前缀和,故可以预处理出前缀和,使得dp[i][j]实现O(1)递推,优化为两层循环。

优化后的代码:

class Solution {
public:
    int numberOfPermutations(int n, vector<vector<int>>& requirements) {
        
        const int mod = 1e9 + 7;
        
        vector<int> vt(305, -1);
        for(auto x: requirements) vt[x[0] + 1] = x[1];

        vector<int> dp(405, 0);
        vector<int> sum(405, 0);
        dp[0] = 1;

        for (int i = 1; i <= n; ++i) 
        {
            sum[0] = dp[0];
            for(int j = 1; j <= min(400, (1 + i) * i / 2); ++j) sum[j] = (sum[j - 1] + dp[j]) % mod;
            if (vt[i] != -1) 
            {
                for(int j = 0; j <= min(400, (1 + i) * i / 2); ++j) dp[j] = 0;
                int j = vt[i];
                if(j < i) dp[j] = sum[j];
                else dp[j] = (sum[j] - sum[j - i] + mod) % mod;
                continue;
            }
            for (int j = 0; j <= min(400, (1 + i) * i / 2); ++j) 
            {
                if(j < i) dp[j] = sum[j];
                else dp[j] = (sum[j] - sum[j - i] + mod) % mod;
            }
        }
        
        return dp[vt[n]];
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1881346.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mini-Contract电子合同在线签署小程序源码

Mini-Contract电子合同在线签署小程序源码&#xff0c;采用的是uniapp Vue3框架搭建&#xff0c;只有前端源码是一个聚合市场上各类电子合同解决方案商的工具&#xff0c;让用户无需一个个对接电子合同厂商&#xff0c;节省时间和精力。该程序提供了简洁的代码和最新的技术栈&a…

C++ | Leetcode C++题解之第208题实现Trie(前缀树)

题目&#xff1a; 题解&#xff1a; class Trie { private:vector<Trie*> children;bool isEnd;Trie* searchPrefix(string prefix) {Trie* node this;for (char ch : prefix) {ch - a;if (node->children[ch] nullptr) {return nullptr;}node node->children[…

现代信息检索笔记(二)

目录 信息检索概述 IR vs数据库: 结构化vs 非结构化数据 结构化数据 非结构化数据 半结构化数据 传统信息检索VS现代信息检索 布尔检索 倒排索引 一个例子 建立词项&#xff08;可以是字、词、短语、一句话&#xff09;-文档的关联矩阵。 关联向量 检索效果的评价 …

【IVI】car_service 命令行工具

【IVI】car_service 命令行工具 1、car_service服务执行2、CarShellCommand命令执行2.1 cmd car_service day-night-mode day设置白天模式2.2 cmd car_service inject-vhal-event vhal信号事件2.2.1 VehiclePropertyIds2.2.2 模拟驾驶事件 2.3 cmd car_service inject-error-ev…

STM32MP135裸机编程:使用软件触发硬件复位

0 参考资料 STM32MP13xx参考手册.pdf 1 使用寄存器实现软件复位 1.1 复位电路概述 重点关注下面标红的路线&#xff1a; 通过这条路线可以清楚看到&#xff0c;我们可以通过设置RCC_MP_GRSTCSETR寄存器让RPCTL&#xff08;复位脉冲控制器&#xff09;给NRST&#xff08;硬件复…

hmall-服务保护和分布式事务

1. 微服务保护 1.1 服务保护方案 1.1.1 请求限流 服务故障最重要原因&#xff0c;就是并发太高&#xff01;解决了这个问题&#xff0c;就能避免大部分故障。当然&#xff0c;接口的并发不是一直很高&#xff0c;而是突发的。因此请求限流&#xff0c;就是限制或控制接口访问…

常见容性负载组应用

什么是容性负载&#xff1f; 在交流系统中&#xff0c;电压和电流随电源的频率而上升和下降。电压和电流是否一起上升取决于负载的特性&#xff0c;负载有三种类型。电阻负载&#xff08;例如加热元件和白炽灯&#xff09;的影响最小&#xff0c;电压和电流一起上升和下降&…

Vue3学习笔记<->创建第一个vue项目(2)

新建一个项目目录 找一个盘新建一个目录&#xff0c;我这里在D盘创建一个vuedemo目录作为项目存放的目录。使用idea打开目录。   单击ieda底部的按钮“Terminal”&#xff0c;打开命令行窗口&#xff0c;如果命令行窗口当前目录不是“vuedemo”&#xff0c;就切换到“vuedem…

九浅一深Jemalloc5.3.0 -- ②浅*size class

目前市面上有不少分析Jemalloc老版本的博文&#xff0c;但5.3.0却少之又少。而且5.3.0的架构与之前的版本也有较大不同&#xff0c;本着“与时俱进”、“由浅入深”的宗旨&#xff0c;我将逐步分析Jemalloc5.3.0的实现。 另外&#xff0c;单讲实现代码是极其枯燥的&#xff0c;…

web渗透-反序列化漏洞

一、简介 就是把一个对象变成可以传输的字符串&#xff0c;目的就是为了方便传输。假设&#xff0c;我们写了一个class,这个class里面存有一些变量。当这个class被实例化了之后&#xff0c;在使用过程中里面的一些变量值发生了改变。以后在某些时候还会用到这个变量&#xff0…

压缩包怎么解压,解压压缩包不损坏文件

常见格式&#xff1a; ZIP&#xff1a;最常见的压缩文件格式之一&#xff0c;支持跨平台。RAR&#xff1a;另一种常见的压缩文件格式&#xff0c;通常压缩率比ZIP高&#xff0c;但不如ZIP普及。7Z&#xff1a;来自7-Zip的压缩格式&#xff0c;支持更高的压缩率和一些高级特性。…

长沙高校大学智能制造实验室数字孪生可视化系统平台建设项目验收

长沙高校大学智能制造实验室始终站在科技前沿&#xff0c;不断探索和实践智能制造的新技术、新方法。数字孪生技术作为智能制造领域的重要分支&#xff0c;其通过将物理世界的实体映射到数字世界&#xff0c;实现对实体的实时监测、模拟和分析&#xff0c;为智能制造提供了强大…

Python | Leetcode Python题解之第208题实现Trie(前缀树)

题目&#xff1a; 题解&#xff1a; class Trie:def __init__(self):self.children [None] * 26self.isEnd Falsedef searchPrefix(self, prefix: str) -> "Trie":node selffor ch in prefix:ch ord(ch) - ord("a")if not node.children[ch]:retur…

解决本机电脑只能通过localhost访问,不能通过127.0.0.1访问

背景问题 有天我启动项目&#xff0c;发现项目连接Mysq总是连接不上&#xff0c;查了url、ip、port、用户名和密码都没有错&#xff0c;就是连接不上mysql数据库&#xff0c;后来通过查找资料发现有多个进程占用3306端口。 pid 6016 是mysqld服务 而pid 9672 是一个叫 svchos…

Python-数据分析组合可视化实例图【附完整源码】

数据分析组合可视化实例图 开篇&#xff1a;应女朋友的要求&#xff0c;于是写下了这篇详细的数据可视化代码及完整注释 一&#xff1a;柱状图、折线图横向组合网格布局 本段代码使用了pyecharts库来创建一个包含多个图表&#xff08;柱状图、折线图&#xff09;和网格布局的…

理想汽车提出3DRealCar:首个大规模3D真实汽车数据集

理想提出3DRealCar&#xff0c;这是第一个大规模 3D 实车数据集&#xff0c;包含 2500 辆在真实场景中拍摄的汽车。我们希望 3DRealCar 可以成为促进汽车相关任务的宝贵资源。 理想汽车提出3DRealCar&#xff1a;首个大规模3D真实汽车数据集! 我们精心策划的高质量3DRealCar数…

帝国CMS(EmpireCMS)漏洞复现

简介 《帝国网站管理系统》英文译为Empire CMS&#xff0c;简称Ecms&#xff0c;它是基于B/S结构&#xff0c;且功能强大而帝国CMS-logo易用的网站管理系统。 帝国CMS官网&#xff1a;http://www.phome.net/ 参考相关漏洞分析文章&#xff0c;加上更详细的渗透测试过程。 参考…

使用Pytho删除docx文档中的页眉和页脚

介绍&#xff1a; 在日常工作中&#xff0c;我们经常需要处理文档&#xff0c;其中包括删除或修改页眉和页脚。本文将介绍如何使用Python编程语言和wxPython模块创建一个简单的GUI应用程序&#xff0c;帮助我们删除docx文档中的页眉和页脚。 C:\pythoncode\new\deleteyemeiyej…

数据结构:期末考 第六次测试(总复习)

一、 单选题 &#xff08;共50题&#xff0c;100分&#xff09; 1、表长为n的顺序存储的线性表&#xff0c;当在任何位置上插入或删除一个元素的概率相等时&#xff0c;插入一个元素所需移动元素的平均个数为&#xff08; D &#xff09;.&#xff08;2.0&#xff09; A、 &am…

51单片机项目-点亮第一个LED灯

目录 新建项目选择型号添加新文件到该项目设置字体和utf-8编码二极管如何区分正负极原理&#xff1a;CPU通过寄存器来控制硬件电路 用P2寄存器的值控制第一个灯亮进制转换编译查看P2寄存器的地址生成HEX文件把代码下载到单片机中下载程序到单片机 新建项目 选择型号 stc是中国…