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

运用逆元优化组合计算#数论

 数论基础知识和模板-CSDN博客

 

问题分析

题目要求统计满足特定条件的排列数目。关键在于:

  1. 从给定的数组中选择两个数作为 n 和 m
  2. 剩余的数必须能够组成 n 个 m 或 m 个 n 的结构
  3. 计算所有可能的有效排列数目

完整

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL MOD = 1e9+7;// 快速幂计算 a^b % MOD
LL qpow(LL a, LL b) {LL res = 1;while (b) {if (b & 1) res = res * a % MOD;a = a * a % MOD;b >>= 1;}return res;
}int main() {int sum; cin >> sum;               // 输入数组长度int scale = sum - 2;              // 目标排列长度 = sum - 2// 预处理阶乘数组 jc[i] = i! % MODvector<LL> jc(500001, 1), invjc(500001);for (int i = 1; i <= 500000; i++) jc[i] = jc[i-1] * i % MOD;// 预处理阶乘的逆元数组 invjc[i] = (i!)^(-1) % MODfor (int i = 0; i <= 500000; i++) invjc[i] = qpow(jc[i], MOD-2);// 统计每个数的出现次数vector<int> bucket(500001);for (int i = 0; i < sum; i++) {int x; cin >> x;bucket[x]++;}LL ans = 0;// 枚举所有可能的因子对 (i, scale/i)for (int i = 1; i <= scale; i++) {if (scale % i == 0 && bucket[i] && bucket[scale/i]) {int n = i, m = scale/i;bucket[n]--; bucket[m]--;  // 临时减少计数// 计算剩余元素的排列数目LL now = jc[scale];for (int j = 1; j <= 500000; j++)if (bucket[j]) now = now * invjc[bucket[j]] % MOD;ans = (ans + now) % MOD;bucket[n]++; bucket[m]++;  // 恢复计数}}cout << ans << endl;return 0;
}

核心算法解析

1. 数学原理
  • 排列数计算:对于长度为 scale 的排列,若元素 x 出现 c_x 次,则排列数为:

    scale! / (c_1! * c_2! * ... * c_k!)
    
     

    在模运算下,除法转换为乘以逆元:a/b ≡ a * b^(-1) (mod MOD)

  • 逆元计算:使用费马小定理 a^(MOD-1) ≡ 1 (mod MOD),因此 a^(-1) ≡ a^(MOD-2) (mod MOD)

2. 预处理优化
  • 阶乘数组jc[i] 存储 i! % MOD,递推公式:jc[i] = jc[i-1] * i % MOD
  • 逆元数组invjc[i] 存储 (i!)^(-1) % MOD,通过快速幂计算:invjc[i] = qpow(jc[i], MOD-2)
3. 因子枚举策略
  • 枚举范围:遍历 i 从 1 到 scale,检查 i 是否是 scale 的因子
  • 条件判断:若 scale % i == 0 且数组中存在足够的 i 和 scale/i,则它们可能是有效解
  • 排列计算:临时减少 i 和 scale/i 的计数,计算剩余元素的排列数并累加
4. 复杂度分析
  • 预处理:阶乘和逆元计算均为 O (N)
  • 枚举因子:O (scale),实际有效因子对数量远小于 scale
  • 排列计算:每次 O (N),但仅在有效因子对时执行
  • 总复杂度:O (N + scale),其中 N = 5e5

 

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

相关文章:

  • [HDLBits] Cs450/timer
  • 工业网络安全新范式——从风险可见性到量化防御的进化
  • 优雅草蜻蜓R实时音视频会议系统技术规划与全球RTC开源技术全景分析·优雅草卓伊凡|麻子|贝贝|clam
  • CentOS系统如何安装和使用docker
  • SpringSSM
  • NV113NV116美光固态闪存NV120NV130
  • 7月2日星期三今日早报简报微语报早读
  • 【一起来学AI大模型】通义千问API入门教程
  • NVIDIA智能汽车技术公开课笔记
  • 【Maven】Maven核心机制的 万字 深度解析
  • Oracle 证书等级介绍
  • Spring AI 源码
  • 全面的 Spring Boot 整合 RabbitMQ 的 `application.yml` 配置示例
  • 将文件使用base64存入数据库并在微信小程序中实现文件下载
  • springboot 显示打印加载bean耗时工具类
  • iOS App无源码安全加固实战:如何对成品IPA实现结构混淆与资源保护
  • python中两种策略模式的实现
  • 2-RuoYi-UI管理平台的启动
  • 大语言模型随意猜测网址引发网络安全危机
  • 零信任安全:重塑网络安全架构的革命性理念
  • 【Unity3D实现加载在线地图——WebGL】
  • 【ABAP】 从无到有 新建一个Webdynpro程序
  • 同一水平的 RISC-V 架构的 MCU,和 ARM 架构的 MCU 相比,运行速度如何?
  • Tomcat log日志解析
  • 【Linux】文件权限以及特殊权限(SUID、SGID)
  • Highcharts 安装使用教程
  • Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
  • flutter flutter_vlc_player播放视频设置循环播放失效、初始化后获取不到视频宽高
  • 机器学习:集成学习方法之随机森林(Random Forest)
  • AWS RDS Aurora全局数据库转区域数据库实战指南:无缝迁移零停机