【模板】组合数取模

2023-10-27

1.利用递推式预处理组合数取模

题目描述

给定 n n n 组询问,每组询问给定两个整数 a , b a, b a,b,请你输出 C a b   m o d   ( 1 0 9 + 7 ) C_a^b \ mod \ (10^9+7) Cab mod (109+7) 的值。

数据范围

1 ≤ n ≤ 10000 1 \le n \le 10000 1n10000

1 ≤ b ≤ a ≤ 2000 1 \le b \le a \le 2000 1ba2000

递推式

C a b = C a − 1 b + C a − 1 b − 1 C_a^b = C_{a-1}^{b}+C_{a-1}^{b-1} Cab=Ca1b+Ca1b1

#include <iostream>
#include <cstdio>

using namespace std;

const int N = 2010, mod = 1e9 + 7;
int c[N][N];

void init()
{
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j <= i; j++)
        {
            if (!j)
            {
                c[i][j] = 1;
            }
            else
            {
                c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
            }
        }
    }
}

int main()
{
    init();
    
    int n;
    scanf("%d", &n);
    
    while (n--)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        printf("%d\n", c[a][b]);
    }
    
    return 0;
}

2.预处理阶乘的余数和阶乘逆元的余数

题目描述

给定 n n n 组询问,每组询问给定两个整数 a , b a, b a,b,请你输出 C a b   m o d   ( 1 0 9 + 7 ) C_a^b\ mod\ (10^9+7) Cab mod (109+7) 的值。

数据范围

1 ≤ n ≤ 10000 1 \le n \le 10000 1n10000

1 ≤ b ≤ a ≤ 1 0 5 1 \le b \le a \le 10^5 1ba105

逆元

a ∗ x ≡ 1   ( m o d   b ) a ∗ x ≡ 1 \ (mod \ b) ax1 (mod b) a a a b b b 互质,那么我们就能定义 x x x a a a 的逆元,记为 a − 1 a^{−1} a1,所以我们也可以称 x x x a a a m o d   b mod\ b mod b 意义下的倒数。

因此,对于 a b   ( m o d   p ) \frac{a}{b}\ (mod\ p) ba (mod p),我们就可以求出 b b b m o d   p mod\ p mod p 下的逆元,然后乘上 a a a,再 m o d   p mod\ p mod p,就是这个分数的值了。

快速幂求逆元

这个做法要利用费马小定理,如下:

p p p 为素数, a a a 为正整数,且 a a a p p p 互质,则有 a p − 1 ≡ 1   ( m o d   p ) a^{p−1} ≡ 1 \ (mod \ p) ap11 (mod p)

可以发现这个式子右边刚好为 1 1 1,因此,代入原式即可得到:

a ∗ x ≡ 1   ( m o d   p ) a ∗ x ≡ 1\ (mod\ p) ax1 (mod p)

a ∗ x ≡ a p − 1   ( m o d   p ) a ∗ x ≡ a^{p−1}\ (mod\ p) axap1 (mod p)

x ≡ a p − 2   ( m o d   p ) x ≡ a^{p−2}\ (mod\ p) xap2 (mod p)

所以我们可以用快速幂来算出 a p − 2   ( m o d   p ) a^{p−2}\ (mod\ p) ap2 (mod p) 的值,这个数就是它的逆元了。

组合数

C a b = a ∗ ( a − 1 ) ∗ . . . ∗ ( a − b + 1 ) b ∗ ( b − 1 ) ∗ . . . ∗ 1 = a ! b ! ∗ ( a − b ) ! C_a^b = \frac{a*(a-1)*...*(a-b+1)}{b*(b-1)*...*1} = \frac{a!}{b!*(a-b)!} Cab=b(b1)...1a(a1)...(ab+1)=b!(ab)!a!

首先,预处理阶乘的余数和阶乘逆元的余数:

f a c t [ i ] = ( i ! )   m o d   ( 1 0 9 + 7 ) fact[i] = (i!)\ mod \ (10^9+7) fact[i]=(i!) mod (109+7)

i n f a c t [ i ] = ( i ! ) − 1   m o d   ( 1 0 9 + 7 ) infact[i] = (i!)^{-1}\ mod\ (10^9+7) infact[i]=(i!)1 mod (109+7)

那么,组合数求解如下:

C a b = f a c t [ a ] ∗ i n f a c t [ b ] ∗ i n f a c t [ a − b ] C_a^{b} = fact[a]*infact[b]*infact[a-b] Cab=fact[a]infact[b]infact[ab]

#include <iostream>
#include <cstdio>

using namespace std;

typedef long long ll;

const int N = 100010, mod = 1e9 + 7;

int fact[N], infact[N];

int qmi(int a, int b, int m)
{
    int res = 1;
    while (b)
    {
        if (b & 1) res = (ll)res * a % mod;
        a = (ll)a * a % mod;
        b >>= 1;
    }
    return res;
}

int main()
{
    // 预处理阶乘的余数和阶乘逆元的余数
    fact[0] = 1, infact[0] = 1;
    for (int i = 1; i < N; i++)
    {
        fact[i] = (ll)fact[i - 1] * i % mod;
        infact[i] = (ll)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
    }
    
    int n;
    scanf("%d", &n);
    
    while (n--)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        printf("%d\n", (ll)fact[a] * infact[b] % mod * infact[a - b] % mod);
    }
    
    return 0;
}

3.卢卡斯定理

题目描述

给定 n n n 组询问,每组询问给定三个整数 a , b , p a,b,p a,b,p,其中 p p p 是质数,请你输出 C a b   m o d   p C_a^b\ mod\ p Cab mod p 的值。

数据范围

1 ≤ n ≤ 20 1 \le n \le 20 1n20

1 ≤ b ≤ a ≤ 1 0 18 1 \le b \le a \le 10^{18} 1ba1018

1 ≤ p ≤ 1 0 5 1 \le p \le 10^5 1p105

Lucas定理

p p p 是质数,则对于任意整数 1 ≤ m ≤ n 1 \leq m \leq n 1mn C n m ≡ C n   m o d   p m   m o d   p ∗ C n / p m / p   ( m o d   p ) C_n^m \equiv C_{n\ mod\ p}^{m\ mod \ p}*C_{n/p}^{m/p}\ (mod\ p) CnmCn mod pm mod pCn/pm/p (mod p)

#include <iostream>
#include <cstdio>

using namespace std;

typedef long long ll;

// 快速幂模板
int qmi(int a, int b, int p)
{
    int res = 1;
    while (b)
    {
        if (b & 1) res = (ll)res * a % p;
        a = (ll)a * a % p;
        b >>= 1;
    }
    return res;
}

// 通过定义求组合数C(a, b)
int C(int a, int b, int p)
{
    if (b > a) return 0;
    
    int res = 1;
    for (int i = 1, j = a; i <= b; i++, j--)
    {
        res = (ll)res * j % p;
        res = (ll)res * qmi(i, p - 2, p) % p;
    }
    return res;
}

int lucas(ll a, ll b, int p)
{
    if (a < p && b < p) return C(a, b, p);
    return (ll)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}

int main()
{
    int n;
    scanf("%d", &n);
    
    while (n--)
    {
        ll a, b;
        int p;
        scanf("%lld%lld%d", &a, &b, &p);
        printf("%d\n", lucas(a, b, p));
    }
    
    return 0;
}

4.将组合数分解质因数+高精度乘低精度

题目描述

输入 a , b a, b a,b,求 C a b C_a^b Cab 的值。注意结果可能很大,需要使用高精度计算。

数据范围

1 ≤ b ≤ a ≤ 5000 1 \le b \le a \le 5000 1ba5000

思路

当我们需要求出组合数的真实值,而非对某个数的余数时,分解质因数的方式比较好用。

C a b = a ∗ ( a − 1 ) ∗ . . . ∗ ( a − b + 1 ) b ∗ ( b − 1 ) ∗ . . . ∗ 1 = a ! b ! ∗ ( a − b ) ! C_a^b = \frac{a*(a-1)*...*(a-b+1)}{b*(b-1)*...*1} = \frac{a!}{b!*(a-b)!} Cab=b(b1)...1a(a1)...(ab+1)=b!(ab)!a!

首先筛选出范围内的所有质数,然后将组合数分解质因数为 p 1 c 1 ∗ p 2 c 2 ∗ . . . ∗ p k c k p_1^{c_1} * p_2^{c_2} * ... * p_k^{c_k} p1c1p2c2...pkck,最后用高精度乘法将所有质因子乘起来即可。

如何求 n ! n! n! 中有多少个质因子 p p p 呢?

⌊ n p ⌋ + ⌊ n p 2 ⌋ + ⌊ n p 3 ⌋ + . . . \lfloor \frac{n}{p} \rfloor+\lfloor \frac{n}{p^2} \rfloor+\lfloor \frac{n}{p^3} \rfloor+... pn+p2n+p3n+...

#include <iostream>
#include <cstdio>
#include <vector>

using namespace std;

const int N = 5010;

int primes[N], cnt;
bool st[N];
int sum[N];

// 线性筛
void get_primes(int n)
{
    for (int i = 2; i <= n; i++)
    {
        if (!st[i]) primes[cnt++] = i;
        for (int j = 0; primes[j] <= n / i; j++)
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}

// 求n!中有多少个质因子p
int get(int n, int p)
{
    int res = 0;
    while (n)
    {
        res += n / p;
        n /= p;
    }
    return res;
}

// 高精度乘以低精度
vector<int> mul(vector<int> a, int b)
{
    vector<int> c;
    int t = 0;
    for (int i = 0; i < a.size(); i++)
    {
        t += a[i] * b;
        c.push_back(t % 10);
        t /= 10;
    }
    while (t)
    {
        c.push_back(t % 10);
        t /= 10;
    }
    return c;
}

int main()
{
    int a, b;
    scanf("%d%d", &a, &b);
    
    get_primes(a);
    
    for (int i = 0; i < cnt; i++)
    {
        int p = primes[i];
        sum[i] = get(a, p) - get(b, p) - get(a - b, p);
    }
    
    vector<int> res;
    res.push_back(1);
    
    for (int i = 0; i < cnt; i++)
    {
        for (int j = 0; j < sum[i]; j++)
        {
            res = mul(res, primes[i]);
        }
    }
    
    for (int i = res.size() - 1; i >= 0; i--)
    {
        printf("%d", res[i]);
    }
    
    return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【模板】组合数取模 的相关文章

  • EF Core Group By 翻译支持条件总和

    听说 EF Core 2 1 将支持翻译小组 我感到非常兴奋 我下载了预览版并开始测试它 但发现我在很多地方仍然没有得到翻译分组 在下面的代码片段中 对 TotalFlagCases 的查询将阻止翻译分组工作 无论如何 我可以重写这个以便我
  • 我如何才能等待多个事情

    我正在使用 C 11 和 stl 线程编写一个线程安全队列 WaitAndPop 方法当前如下所示 我希望能够将一些内容传递给 WaitAndPop 来指示调用线程是否已被要求停止 如果 WaitAndPop 等待并返回队列的元素 则应返回
  • 在哪里可以找到列出 SSE 内在函数操作的官方参考资料?

    是否有官方参考列出了 GCC 的 SSE 内部函数的操作 即 头文件中的函数 除了 Intel 的 vol 2 PDF 手册外 还有一个在线内在指南 https www intel com content www us en docs in
  • 用于检查类是否具有运算符/成员的 C++ 类型特征[重复]

    这个问题在这里已经有答案了 可能的重复 是否可以编写一个 C 模板来检查函数是否存在 https stackoverflow com questions 257288 is it possible to write a c template
  • Asp.NET WebApi 中类似文件名称的路由

    是否可以在 ASP NET Web API 路由配置中添加一条路由 以允许处理看起来有点像文件名的 URL 我尝试添加以下条目WebApiConfig Register 但这不起作用 使用 URIapi foo 0de7ebfa 3a55
  • 为什么当实例化新的游戏对象时,它没有向它们添加标签? [复制]

    这个问题在这里已经有答案了 using System Collections using System Collections Generic using UnityEngine public class Test MonoBehaviou
  • BitTorrent 追踪器宣布问题

    我花了一点业余时间编写 BitTorrent 客户端 主要是出于好奇 但部分是出于提高我的 C 技能的愿望 我一直在使用理论维基 http wiki theory org BitTorrentSpecification作为我的向导 我已经建
  • 不同枚举类型的范围和可转换性

    在什么条件下可以从一种枚举类型转换为另一种枚举类型 让我们考虑以下代码 include
  • C++ OpenSSL 导出私钥

    到目前为止 我成功地使用了 SSL 但遇到了令人困惑的障碍 我生成了 RSA 密钥对 之前使用 PEM write bio RSAPrivateKey 来导出它们 然而 手册页声称该格式已经过时 实际上它看起来与通常的 PEM 格式不同 相
  • 重载<<的返回值

    include
  • 如何序列化/反序列化自定义数据集

    我有一个 winforms 应用程序 它使用强类型的自定义数据集来保存数据进行处理 它由数据库中的数据填充 我有一个用户控件 它接受任何自定义数据集并在数据网格中显示内容 这用于测试和调试 为了使控件可重用 我将自定义数据集视为普通的 Sy
  • 什么时候虚拟继承是一个好的设计? [复制]

    这个问题在这里已经有答案了 EDIT3 请务必在回答之前清楚地了解我要问的内容 有 EDIT2 和很多评论 有 或曾经 有很多答案清楚地表明了对问题的误解 我知道这也是我的错 对此感到抱歉 嗨 我查看了有关虚拟继承的问题 class B p
  • 如何查看网络连接状态是否发生变化?

    我正在编写一个应用程序 用于检查计算机是否连接到某个特定网络 并为我们的用户带来一些魔力 该应用程序将在后台运行并执行检查是否用户请求 托盘中的菜单 我还希望应用程序能够自动检查用户是否从有线更改为无线 或者断开连接并连接到新网络 并执行魔
  • 覆盖子类中的字段或属性

    我有一个抽象基类 我想声明一个字段或属性 该字段或属性在从该父类继承的每个类中具有不同的值 我想在基类中定义它 以便我可以在基类方法中引用它 例如覆盖 ToString 来表示 此对象的类型为 property field 我有三种方法可以
  • 链接器错误:已定义

    我尝试在 Microsoft Visual Studio 2012 中编译我的 Visual C 项目 使用 MFC 但出现以下错误 error LNK2005 void cdecl operator new unsigned int 2
  • 对现有视频添加水印

    我正在寻找一种用 C 在视频上加水印的方法 就像在上面写文字一样 图片或文字标签 我该怎么做 谢谢 您可以使用 Nreco 视频转换器 代码看起来像 NReco VideoConverter FFMpegConverter wrap new
  • WPF/C# 将自定义对象列表数据绑定到列表框?

    我在将自定义对象列表的数据绑定到ListBox in WPF 这是自定义对象 public class FileItem public string Name get set public string Path get set 这是列表
  • 向现有 TCP 和 UDP 代码添加 SSL 支持?

    这是我的问题 现在我有一个 Linux 服务器应用程序 使用 C gcc 编写 它与 Windows C 客户端应用程序 Visual Studio 9 Qt 4 5 进行通信 是什么very在不完全破坏现有协议的情况下向双方添加 SSL
  • 如何从两个不同的项目中获取文件夹的相对路径

    我有两个项目和一个共享库 用于从此文件夹加载图像 C MainProject Project1 Images 项目1的文件夹 C MainProject Project1 Files Bin x86 Debug 其中有project1 ex
  • C++ 中类级 new 删除运算符的线程安全

    我在我的一门课程中重新实现了新 删除运算符 现在我正在使我的代码成为多线程 并想了解这些运算符是否也需要线程安全 我在某处读到 Visual Studio 中默认的 new delete 运算符是线程安全的 但这对于我的类的自定义 new

随机推荐

  • 怎么判断ios设备、移动设备、浏览器

    Navigator Navigator接口表示用户代理的状态和标识 允许脚本查询它和注册一些自己的服务 我们可以通过window navigator来访问Navigator对象 常用属性 Navigator appVersion 浏览器版本
  • git-创建release

    git tag a v0 1 1 m Release test git push origin v0 1 1
  • 前端开发微信支付宝支付流程

    微信支付的流程 我认为有几种方案 微信支付 async payOrder 1 创建订单 const orderInfo order price 0 1 consignee addr this addstr goods this cart f
  • 什么是缓冲区?(详细!!!!!干货!!!!!)

    缓冲区 缓冲区其实是不存在的 只不过是我们认为想象出来的 1 把数据写入文件之前 会先写入缓冲区 刷新时才会写入文件内 2 我们所说的缓冲区 实际 只有库函数中存在 3 文件流指针所应用的 文件描述符没有 知识点 1 使用printf向文件
  • 关于Gitlab恼人的Git无权限访问问题解决

    问题 不知什么时候起 从gitlab com上新开的项目中拿代码时 冒出ERROR The project you were looking for could not be found or you don t have permissi
  • docker-compose重新启动Mysql报错changing ownership of ‘/var/lib/mysql/mysql.sock‘: No such file or direct

    一 背景 最近在使用 docker compose 编排整合一个项目 springboot mysql 的时候 首次启动后重新再启动的时候 mysql 容器启动失败 通过 docker logs 命令查看 mysql 容器的启动日志如下 c
  • ajax穿formdata,ajax formdata格式问题

    慕容708150 貌似是因为没有name属性 修改如下 HTML 发布评论JavaScript function postComment var commentForm document getElementById comment for
  • apache转发tomcat http转https

    最近在弄小程序 而小程序网络请求所需要的链接需要https安全链接 之前胡乱配置一番可以用了 不过并不太理解 后来又需要一个php项目 各处查看了一下 需要apache服务器 而我的只有一个域名 已经给了tomcat了 如果在域名后面加端口
  • 2020-10-07

    渗透测试 U盘监控器 1 打开USB监控器 注册时输入任意注册码 出现注册失败页面 2 在Winhex打开USB监控器 exe 文本搜索 注册失败 之后推出字符串文件偏移地址为0x81A79 引用该字符串的指令在字符串地址的常量为0x048
  • Java09

    一 继承 在Java中 使用关键字extends来继承类 父类 public class Fu int num 100 public void methodfu System out println num 子类继承 关键字 public
  • dns服务器项目实例,DNS服务器配置实例-----主DNS服务器

    DNS服务器配置简单实例 主DNS服务器 DNS服务器类型 主DNS服务器 master 辅助DNS服务器 slave 高速缓存服务器 hint 安装bind三部曲 1 查询包是否已经安装 Nborn root 08 06 rpm q bi
  • esp32 Micropython驱动ST7735 1.8寸TFT屏幕 中文显示;时间显示、网络network实时时间获取utptime;urequests、upip等包安装

    参考 https blog csdn net weixin 57604547 article details 122274614 0 线连接 IO就是GPIO引脚 ESP32 TFT 屏ST7735 GND GND 3 3V VDD IO2
  • springboot集成shiro

    这里写自定义目录标题 Springboot集成shiro Shiro介绍 springboot集成shiro Springboot集成shiro Shiro介绍 Shiro是Apache 的一个开源项目 是一个java的安全框架具有认证 授
  • Open Euler学习

    Open Euler学习 目录 Open Euler学习 Open Euler安装截图 使用MobaXterm exe软件 连接自己的操作系统 作业问题 1 使用什么命令查看 ip 地址及接口信息 2 cp和mv命令有什么区别 用什么指令将
  • EM算法推导(收敛性证明和在GMM中的应用)

    一 EM算法的提出 当你有一组数据像如下这样 Note picture source 显然用单个高斯分布模型去拟合它们效果不好 这是一个典型的高斯混合模型的例子 p X
  • TypeError: strptime() takes no keyword arguments ValueError(“‘%s‘ is a bad directive in format ‘%s‘“

    t datetime datetime strptime 2021 5 12 09 28 11 format Y m d h m s 1 错误原因 参数格式不匹配 strptime定义 def strptime data string fo
  • leveldb(六):key的不同种类型

    有5个key的概念 可能会让人混淆 下面就来一个一个的分析 User key 最简单的key了 就是用户传入的数据 Slice user key ParsedInternalKey enum ValueType kTypeDeletion
  • sqlite3交叉编译

    1 交叉编译sqllite3可以先从官网下载最新最新的源码进行编译 sqlite3下载sqlite3有两种版本的源代码 sqlite amalgamation 3300100 zip这种是将所有的操作放到sqlite3中进行使用的 虽然官方
  • 特征筛选1——根据方差筛选(单变量筛选)

    根据给定方差的阈值 删除掉值变化小的维度 以此降低数据规模 当把阈值设置为0的时候 就会删除没有变化的数据 示例 import numpy as np from sklearn feature selection import Varian
  • 【模板】组合数取模

    文章目录 1 利用递推式预处理组合数取模 2 预处理阶乘的余数和阶乘逆元的余数 3 卢卡斯定理 4 将组合数分解质因数 高精度乘低精度 1 利用递推式预处理组合数取模 题目描述 给定 n n n 组询问 每组询问给定两个整数 a