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

【算法精解】逆序对受限的方案数

题目:给定两个数 n , k ,你需要求出 1 , 2 , . . . , n 的所有排列 a 1 , a 2... , a n 中满足 a 1 < a 2 且逆序对个数 s u m ≤ k 的个数 , 答案对 1 0 9 + 7 取模 题目:给定两个数n,k,你需要求出1,2,...,n的所有排列 a1,a2...,an中满足a1 < a2且逆序对个数sum ≤ k的个数,答案对10^9+7取模 题目:给定两个数nk,你需要求出12...n的所有排列a1,a2...an中满足a1a2且逆序对个数sumk的个数,答案对1097取模
输入描述
一行两个数 n , k , 3 ≤ n ≤ 200 , 0 ≤ k ≤ 200 一行两个数n,k, 3 ≤n≤ 200,0≤k≤200 一行两个数n,k,3n200,0k200
输出描述
输出一行一个数代表答案

解题思路

为了高效地解决这个问题,我们需要利用动态规划 (DP) 来计算满足条件的排列数。具体步骤如下:

1. 期望递减序列:

  • 在一个排列中,逆序对是指对于任意的 i < j ,如果 a i > a j ,则 ( i , j ) i < j,如果 ai > aj,则 (i, j) i<j,如果ai>aj,则(i,j) 是一个逆序对。
  • 我们需要计算的总逆序对数 s u m sum sum 是整个排列中的所有逆序对的数量。

2. 基本思路:

  • 首先,考虑所有排列中满足 a1 < a2 的情况。
  • 对于每一对可能的 (a1, a2) 组合,计算剩余的 n-2 个元素如何排列,使得整个排列的逆序对数 ≤ k。
  • 将所有符合条件的 (a1, a2) 组合的排数相加,得到总解答。

3. 计算步骤:

Step 1: 枚举 a1 和 a2
  • a1 可取值 1 到 n-1 的值。
  • 对于每一对 a1,a2 可以取 a1 + 1 到 n 的值 (因为 a1 < a2)。
Step 2: 计算基础逆序对数
  • 当 a1 和 a2 确定在排列的前两位时,逆序对数主要来自以下几个方面:

    • 与 a1 和 a2 相关的逆序对:

      • 如果 x < a1,则 x 会与 a1 和 a2 形成两个逆序对。
      • 如果 a1 ≤ x < a2,则 x 只会与 a2 形成一个逆序对。
      • 如果 x ≥ a2,则 x 不会与 a1 和 a2 形成逆序对。
    • 通常来说,准备解析的部分对应的是剩余的逆序对。

Step 3: 动态规划计算剩余元素的逆序对数
  • 定义 d p [ s ] [ t ] dp[s][t] dp[s][t] 表示 s 个元素的排列中包括 t 个逆序对的排列数。

  • 递推公式:

    d p [ s ] [ t ] = ∑ l = 0 m i n ( s − 1 , t ) d p [ s − 1 ] [ t − l ] dp[s][t] = \sum_{l=0}^{min(s-1,t)} dp[s-1][t-l] dp[s][t]=l=0min(s1,t)dp[s1][tl]

    其中,l 表示新加的 s 个元素可能会增加的逆序对的数量,插入位置的不同会导致逆序对数的变化。

  • 初始条件:

    d p [ 0 ] [ 0 ] = 1 dp[0][0] = 1 dp[0][0]=1

    表示没有元素时,只有一种排列 (空排列),逆序对数为 0。

Step 4: 确认理想解和
  • 为了快速计算 d p [ s ] [ 0 ] dp[s][0] dp[s][0] d p [ s ] [ t m ] dp[s][t_m] dp[s][tm] 的累加和,预先计算前缀和 p r e f i x s u m [ s ] [ t ] prefix_sum[s][t] prefixsum[s][t]

    p r e f i x s u m [ s ] [ t ] = ∑ x = 0 t d p [ s ] [ x ] prefix_sum[s][t] = \sum_{x=0}^{t} dp[s][x] prefixsum[s][t]=x=0tdp[s][x]

  • 这样,在后续计算时,可以通过 p r e f i x s u m [ s ] [ t m a x ] prefix_sum[s][t_max] prefixsum[s][tmax] 快速得到 d p [ s ] [ 0 ] 到 d p [ s ] [ t m a x ] dp[s][0] 到 dp[s][t_max] dp[s][0]dp[s][tmax] 的和。

Step 5: 求总答案
  • 对于每一对 (a1, a2),计算基础逆序对数 b a s e I n v e r s i o n = a 1 + a 2 − 3 baseInversion = a1 + a2 - 3 baseInversion=a1+a23

  • 解释: c 1 = a 1 − 1 c1 = a1 - 1 c1=a11 (小于 a1 的元素数量), c 2 = a 2 − a 1 − 1 c2 = a2 - a1 - 1 c2=a2a11 (在 a1 和 a2 之间的元素数量),则 base_inversion = 2 ∗ c 1 + c 2 = 2 ∗ ( a 1 − 1 ) + ( a 2 − a 1 − 1 ) = a 1 + a 2 − 3 2*c1 + c2 = 2*(a1 - 1) + (a2 - a1 - 1) = a1 + a2 - 3 2c1+c2=2(a11)+(a2a11)=a1+a23

  • 计算剩余允许的逆序对数 t m a x = k − b a s e I n v e r s i o n t_max = k - baseInversion tmax=kbaseInversion

    • 如果 t_max < 0,则这 (a1, a2) 组合不可能满足条件,跳过。
    • 否则,累加 prefix_sum[n-2][t_max] 到答案中。
  • 最终,所有符合条件的 (a1, a2) 组合的排数相加即是答案。

package com.sky;import java.util.Scanner;public class Test1 {static final int MOD = 1_000_000_007;public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt(), k = sc.nextInt();long[][] dp = new long[n - 1][k + 1];dp[0][0] = 1;for (int s = 1; s <= n - 2; ++s) {for (int t = 0; t <= k; ++t) {dp[s][t] = 0;for (int l = 0; l <= Math.min(s - 1, t); ++l) {dp[s][t] = (dp[s][t] + dp[s - 1][t - l]) % MOD;}}}long[][] prefix = new long[n - 1][k + 1];for (int s = 0; s <= n - 2; ++s) {prefix[s][0] = dp[s][0];for (int t = 1; t <= k; ++t) {prefix[s][t] = (prefix[s][t - 1] + dp[s][t]) % MOD;}}long ans = 0;for (int a1 = 1; a1 <= n - 1; ++a1) {for (int a2 = a1 + 1; a2 <= n; ++a2) {long baseInv = a1 + a2 - 3;if (baseInv > k) continue;int invMax = k - (int) baseInv;if (n - 2 == 0) {if (invMax >= 0) {ans = (ans + 1) % MOD;}continue;}if (invMax > k) invMax = k;ans = (ans + prefix[n - 2][invMax]) % MOD;}}System.out.println(ans);}
}

相关文章:

  • 银河麒麟桌面操作系统如何添加WPS字体
  • ControllerAdvice定义统一异常处理
  • 【力扣 | SQL题 | 每日三题】力扣175, 176, 181
  • CloudMusic:免费听歌
  • python功能测试
  • Tableau|一入门
  • error -- unsupported GNU version gcc later than 10 are not supported;(gcc、g++)
  • 网络编程(6)——发送的时序性,全双工通信
  • 一个 Java 语言简化处理 PDF 的框架,提供了一套简单易用的 API 接口,满足多样化需求又能简化开发流程的处理方案(附教程)
  • 【AD那些事 10 】焊盘如何修改为自己想要的形状!!!!! 焊盘设计规则如何更改??????
  • 【架构设计】同步与异步:应用场景与选择指南
  • cpu路、核、线程、主频、缓存
  • 相似度度量方法有哪些?
  • 数据结构--单链表
  • 创建Express后端项目
  • CentOS 7 防火墙操作
  • ES学习笔记(10)--ES6中的函数和数组补漏
  • Golang-长连接-状态推送
  • Javascript 原型链
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • SpiderData 2019年2月25日 DApp数据排行榜
  • 百度小程序遇到的问题
  • 电商搜索引擎的架构设计和性能优化
  • 关于Flux,Vuex,Redux的思考
  • 力扣(LeetCode)56
  • 思考 CSS 架构
  • 延迟脚本的方式
  • 一文看透浏览器架构
  • shell使用lftp连接ftp和sftp,并可以指定私钥
  • #pragma multi_compile #pragma shader_feature
  • #Spring-boot高级
  • #快捷键# 大学四年我常用的软件快捷键大全,教你成为电脑高手!!
  • (23)mysql中mysqldump备份数据库
  • (3)(3.2) MAVLink2数据包签名(安全)
  • (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上
  • (9)YOLO-Pose:使用对象关键点相似性损失增强多人姿态估计的增强版YOLO
  • (cljs/run-at (JSVM. :browser) 搭建刚好可用的开发环境!)
  • (poj1.3.2)1791(构造法模拟)
  • (笔记自用)LeetCode:快乐数
  • (顶刊)一个基于分类代理模型的超多目标优化算法
  • (附表设计)不是我吹!超级全面的权限系统设计方案面世了
  • (附源码)php新闻发布平台 毕业设计 141646
  • (十)DDRC架构组成、效率Efficiency及功能实现
  • ****三次握手和四次挥手
  • .mysql secret在哪_MYSQL基本操作(上)
  • .Net调用Java编写的WebServices返回值为Null的解决方法(SoapUI工具测试有返回值)
  • .NET精简框架的“无法找到资源程序集”异常释疑
  • @AliasFor注解
  • @EnableWebSecurity 注解的用途及适用场景
  • @SuppressWarnings注解
  • [AR]Vumark(下一代条形码)
  • [CISCN2019 华东南赛区]Web4
  • [Codeforces] number theory (R1600) Part.11
  • [Flutter] extends、implements、mixin和 abstract、extension的使用介绍说明
  • [Foreman]解决Unable to find internal system admin account