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

组合计数 + 拓扑序计数问题

目录

题目描述

问题分析

一、核心规则

二、关键结论

三、解题思路

拓展:逆元是什么?


题目描述


问题分析

一、核心规则

  1. 操作只有两种:INSERT idDELETE id
  2. 合法执行顺序的要求:
    • INSERT id必须在DELETE id之前执行(因为插入后才能删除)。
    • 初始执行顺序是合法的,且同一id只会出现一次INSERT和一次DELETE(或者只出现INSERT)。
    • 调整顺序后,最终数据库状态要和原顺序执行后的结果一致:
    • 最终状态里,存在的id是那些只执行了INSERT、没有执行DELETE的记录。
    • 被删除的id必须执行过INSERTDELETE,且INSERT在前。

二、关键结论

  • 对于每个id
    • 如果它有INSERTDELETE:这两条操作必须满足INSERTDELETE之前,是一个固定的先后约束。
    • 如果它只有INSERT:这条操作没有后续约束,只要不违反其他id的约束即可。
    • 如果它只有DELETE:题目保证原顺序合法,这种情况不存在(因为DELETE时必须存在该id,说明前面一定有INSERT)。
  • 所有合法顺序,就是满足所有INSERT(id) → DELETE(id)约束的拓扑序数量。

三、解题思路

  1. 预处理操作

    • 记录每个idINSERTDELETE操作是否存在。
    • 把所有操作分为两类:
      • 成对操作:(INSERT, DELETE),共k对。
      • 单条操作:仅INSERT,共m条。
    • 总操作数n = 2*k + m
  2. 计数公式推导

    • 我们先把n个操作全排列,有n!种方式。
    • 对于每一对(INSERT, DELETE),其中INSERTDELETE前的情况,只占所有排列的一半(每对的两种顺序中只有一种合法)。
    • 因此,总合法顺序数为: \(\text{ans} = \frac{n!}{2^k}\) 其中kINSERTDELETE成对的数量。
  3. 实现要点

    • 因为结果可能很大,通常题目会要求对1e9+7取模,我们用预处理阶乘 + 快速幂求逆元来计算。
    • 2^k的逆元可以用pow(2, k, MOD)的逆元计算。

Java 代码实现

import java.util.*; public class Main { static final int MOD = 1000000007; static final int MAX = 200010; // 假设 N 最大为 2e5 static long[] fact = new long[MAX]; // 快速幂 static long qpow(long a, long b) { long res = 1; while (b > 0) { if ((b & 1) == 1) { res = res * a % MOD; } a = a * a % MOD; b >>= 1; } return res; } public static void main(String[] args) { Scanner sc = new Scanner(System.in); int N = sc.nextInt(); sc.nextLine(); // 预处理阶乘,fact[i] 存储 i! % MOD,方便后续直接取用 fact[0] = 1; for (int i = 1; i <= N; i++) { fact[i] = fact[i - 1] * i % MOD; } Map<Integer, Boolean> hasInsert = new HashMap<>(); Map<Integer, Boolean> hasDelete = new HashMap<>(); for (int i = 0; i < N; i++) { String line = sc.nextLine(); String[] parts = line.split(" "); if (parts[0].equals("INSERT")) { int id = Integer.parseInt(parts[1]); hasInsert.put(id, true); } else if (parts[0].equals("DELETE")) { int id = Integer.parseInt(parts[1]); hasDelete.put(id, true); } } // 统计成对的数量 k:遍历所有 INSERT 的 id,如果该 id 同时有 DELETE,则 k++ int k = 0; for (int id : hasInsert.keySet()) { if (hasDelete.containsKey(id)) { k++; } } // 计算 n! / (2^k) mod MOD long numerator = fact[N]; long denominator = qpow(2, k); long invDenominator = qpow(denominator, MOD - 2); // 费马小定理求逆元 long ans = numerator * invDenominator % MOD; System.out.println(ans); } }

拓展:逆元是什么?

逆元就是在模运算里把除法变成乘法,从而避免除法带来的问题(比如溢出、无法整除)

在模运算里,我们没法直接做除法。 比如:

  • 正常数学里,a ÷ b = a × (1/b)
  • 但在模运算里,1/b这个分数不存在,我们需要找一个整数inv(b),让它满足:
  • 这个inv(b),就叫做b在模MOD下的乘法逆元

有了逆元,除法就可以转换成乘法:

逆元怎么求?(费马小定理)

MOD是一个质数(比如题目里的1e9+7),且b(要除的那个数) 和MOD互质时,我们可以用费马小定理快速求逆元:

总结

  • 逆元的本质:模运算里的 “倒数”,让除法变成乘法。
  • 核心作用
    1. 解决模运算中无法直接做除法的问题
    2. 避免大数除法导致的溢出和计算错误
  • 使用前提:模数MOD是质数,且除数bMOD互质(题目里的21e9+7就满足)。
http://www.jsqmd.com/news/928395/

相关文章:

  • 护发精油功效对比测评:抚平毛躁哪家强? - 资讯快报
  • Downkyi哔哩下载姬:如何快速免费获取B站高清视频的完整教程
  • Win11下JLink驱动安装与激活避坑指南:从6.14版本到V6.40b的完整流程
  • 260亿美元估值!Cognition AI融资背后,AI编程赛道机遇与挑战并存
  • 第四章综合实验
  • AI搜索变革下SEO策略重塑:从关键词到意图理解的技术演进
  • 为什么92%的用户写不出合格古风诗?——Gemini诗歌生成的5个隐性约束条件与绕过方案
  • 伐度司他Vadadustat对比促红细胞生成素治疗非透析慢性肾脏病的血红蛋白波动
  • 2026 乐清黄金回收|铂金钻石 K 金名表名包回收靠谱商家推荐 - 同城好物推荐官
  • 昆明除甲醛公司口碑排行榜:绿舒环保等5家深度测评 - 绿舒环保母婴除甲醛
  • Python进阶 网络编程笔记-多进程
  • Vue版电子病历前端工程包:31个开箱即用组件+多语言HTML页面+配套工具脚本
  • 百度网盘下载加速终极指南:3种方法突破限速实现高速下载
  • 告别Docker Hub抽风:手把手教你用SSH给群晖NAS安装ddns-go动态域名
  • 基于精调大语言模型与双重校验机制构建高精度领域知识图谱
  • 从抓取到理解:爬虫工程师如何向大模型开发转型
  • AI时代表达困境:算法如何重塑创作与个体如何夺回话语权
  • 2026年类似OpenClaw但无安全风险的软件推荐:支持内网部署的OpenClaw替代品TOP榜——龙虾国产化替代方案选型指南 - 品牌2025
  • 260亿美元估值!Cognition如何在AI编程赛道完成转身,成企业软件工程新入口?
  • Dictionary的底层原理
  • GPT-3技术解析:从Transformer架构到应用实践
  • 极限运动场施工为什么不能只看效果图? - 长华体育
  • M1/M2 Mac到手后,我这样配置Java开发环境(JDK 8 + Maven + MySQL 8.0)
  • 数据科学家核心算法工具箱:从PCA到深度学习实战指南
  • 微信小程序图书商城毕业设计全套资料(含可运行源码、论文、PPT与数据库设计)
  • 杭州黄金回收市场乱象调查:如何避开隐性收费陷阱 - 黄金上门回收
  • 计组课设求助
  • 基于机器学习的智能电表用电异常检测与负荷预测系统实战
  • 2026年5月邯郸靠谱黄金回收门店实测盘点:余生黄金回收984元/克领跑,全城6家口碑排行 - 余生黄金回收
  • 阿里、字节 AI 战略大不同:一个“卖货”,一个“做产品”,上市与否成关键因素