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

相关文章:

  • monorepo + Turborepo --- 构建仓库结构
  • 创客匠人解构知识付费爆单密码:产品力打造与 IP 变现的深度耦合
  • [转载]数据库锁分布式锁实现接口幂等性
  • 如何将文件从 iPhone 传输到 Android(新指南)
  • BUUCTF在线评测-练习场-WebCTF习题[ZJCTF 2019]NiZhuanSiWei1-flag获取、解析
  • 02-更换证件背景
  • 节点小宝内网穿透实测:告别“无网”烦恼,让你的设备“触手可及”
  • python实现基于资金分布、RSI及布林策略的方案
  • 智慧赋能高压并网:分布式光伏监控系统在5.88MW物流园项目的实践解析
  • [环境配置] 3. 使用 UV管理 Python 环境
  • 416. 分割等和子集
  • docker拉取redis并使用
  • STEP-BACK PROMPTING:退一步:通过抽象在大型语言模型中唤起推理能力
  • MySQL的5.0和8.0版本区别
  • 基于[coze][dify]搭建一个智能体工作流,使用第三方插件抓取热门视频数据,自动存入在线表格
  • vscode 下 LaTeX 使用配置
  • (一)大语言模型的关键技术<-AI大模型构建
  • Redis搭建集群模式
  • 微信小程序入门实例_____打造你的专属单词速记小程序
  • MAC 多应用切换技巧,单应用切换技巧
  • 文心快码答用户问|Comate AI IDE专场
  • C#调用C++导出的dll怎么调试进入C++ DLL源码
  • 生产环境下载功能OOM问题复盘
  • 学习笔记(29):训练集与测试集划分详解:train_test_split 函数深度解析
  • 科技有温度:七彩喜智慧康养平台,为银发生活织就“数字守护网”
  • 【Vue入门学习笔记】Vue核心语法
  • 飞算 JavaAI 智控引擎:全链路开发自动化新图景
  • Active-Prompt:让AI更智能地学习推理的革命性技术
  • 纹理贴图算法研究论文综述
  • 【leetcode算法300】:哈希板块