当前位置: 首页 > 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.lryc.cn/news/579099.html

相关文章:

  • Django服务开发镜像构建
  • C++主流编辑器特点比较
  • Java 并发编程的 CAS(Compare and Swap)是什么?
  • 讲解“/etc/ssh/sshd_config “的“HostKey /etc/ssh/ssh_host_ed25519_key“ 笔记250702
  • pdf删除一页 python实现(已验证)
  • 模板编译原理
  • 使用OpenCV识别图片相似度评分的应用
  • YOLOv11剪枝与量化(一)模型压缩的必要性
  • 深入理解C++11原子操作:从内存模型到无锁编程
  • SpringCloud系列(47)--SpringCloud Bus实现动态刷新定点通知
  • 04-动态规划
  • 数学建模_微分方程
  • 内存架构的十字路口:深入解析统一内存访问(UMA)与非一致内存访问(NUMA)
  • 虚拟机知识点-Vagrant 在通过 VirtualBox 启动 CentOS 虚拟机时失败-VERR_NEM_VM_CREATE_FAILED
  • 从0开始学习R语言--Day36--空间杜宾模型
  • maven仓库
  • WSL2 + Docker Desktop 环境中查看本地镜像
  • 【Vue入门学习笔记】Vue核心语法
  • CentOS 卸载docker
  • 移动conda虚拟环境的安装目录
  • mongo常用命令
  • odoo17 警示: selection attribute will be ignored as the field is related
  • Node.js-http模块
  • Day04:玩转标准库中的数据处理与日志记录
  • Chart.js 安装使用教程
  • 基于SpringBoot和Leaflet的区域冲突可视化系统(2025企业级实战方案)
  • VC Spyglass:工具简介
  • React Native 开发环境搭建--window--android
  • 24年京东秋季笔试题
  • CSS外边距合并(塌陷)全解析:原理、场景与解决方案