又双叒叕来水数论了

今天来学习\(Lucas \:\ \& \:\ Catalan Number\)

两者有着密切的联系(当然还有CRT),所以放在一起学习一下

\(Lucas\)

定义\(\&\)性质

\(Lucas\)定理是用来求 $C_n^m mod :\ p \(的值。
其中\)n\(和\)m\(是非负整数,\)p\(是素数。
一般用于\)m,n\(很大而\)p\(很小,抑或是\)n,m\(不大但是大于\)p$的情况下来求结果。

用处\(\&\)背景

目前我们学过几个用来求组合数的方法

  • 最暴力的杨辉三角,用二维数组解决,复杂度\(O(n^2)\) 效率低下而且由于数组的原因只能处理很小的数据
  • 将组合式\(C_{n+m}^n \% mod\)转换为\(\frac {(m+n)!} {n! m!} \%mod\),由于除法不可以边除边取\(mod\)所以在处理分母的时候选用了费马小定理,运用逆元的乘法解决。

    看分子的话,\((m+n)!\)在遍历的时候若有元素\(i>mod\),那么取\(mod\)之后整个式子的值就会变成0,而\(Lucas\)的出现,就是为了解决这一问题

引入

针对上述第二种情况,我们先来看一道例题

旗木双翼

题目描述

菲菲和牛牛在一块n行m列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手。

棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落子,直到填满棋盘时结束。落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且这个格子的左侧及上方的所有格子内都有棋子。

_Itachi听说有不少学弟在省选现场AC了D1T1,解决了菲菲和牛牛的问题,但是_Itachi听说有的人认为复杂度玄学,_Itachi并不想难为学弟学妹,他想为大家节约时间做剩下的题,所以将简化版的D1T1带给大家。

_Itachi也在一块n行m列的棋盘上下棋,不幸的是_Itachi只有黑棋,不过幸好只有他一个人玩。现在,_Itachi想知道,一共有多少种可能的棋局(不考虑落子顺序,只考虑棋子位置)。

_Itachi也不会为难学弟学妹们去写高精度,所以只需要告诉_Itachi答案mod 998244353(一个质数)的结果。

输入格式

第一行包括两个整数n,m表示棋盘为n行m列。

输出格式

一个整数表示可能的棋局种数。

样例输入

10 10

样例输出

184756

数据范围与提示

对于 \(20\%\)的数据$n,m \leq10 $

对于 \(30\%\)的数据$n,m\leq20 $

另有 \(20\%\)的数据$n\leq5 $

另有 \(20\%\)的数据$m\leq5 $

对于\(100\%\)的数据$n,m\leq100000 $

solution

可以看到题目当中直接给出了\(mod\)为一个大质数

而且\(m+n\)最大也才二十万,远远小于\(mod\)的数值

所以不会出现取完\(mod\)为\(0\)的情况,所以运用逆元求解即可

\[C_{n+m}^m =\frac {(m+n)!} {n!*m!} \% mod
\]

Code

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define int long long
using namespace std; inline int read(){
int x = 0, w = 1;
char ch = getchar();
for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return x * w;
} const int mod = 998244353; inline int power(int a, int b){
int ans = 1;
while(b){
if(b & 1) ans = (ans % mod) * (a % mod) % mod;
a = (a % mod) * (a % mod) % mod;
b >>= 1;
}
ans %= mod;
return ans;
} signed main(){
int n = read(), m = read();
int tmp = 1;
for(int i = m + n; i >= 1; i--){
tmp *= i;
tmp %= mod;
}
int n1 = 1;
int m1 = 1;
for(int i = 1; i <= n; i++){
n1 *= i;
n1 %= mod;
}
for(int i = 1; i <= m; i++){
m1 *= i;
m1 %= mod;
}
int ans = (tmp % mod) * power(n1 ,mod - 2) % mod * power(m1, mod - 2) % mod;
ans %= mod;
cout << ans << endl;
return 0;
}

如果\(mod\)很小

上述算法显然在求阶乘的时候会变成\(0\)

这就需要\(Lucas\)定理了

性质

性质1

\[Lucas(n,m,p)=cm(n\%p,m\%p)*Lucas(\frac n p,\frac m p,p)
\]

\[Lucas(x,0,p) =1
\]

其中

\[cm(a,b)=a!*(b!*(a-b)!)^{p-2} (mod \:\ p)
\]

\((a-b)!^{p-2}\)为\(a-b\)的逆元,所以可以除一下把式子变成

\[(a!/(a-b)!)*(b!)^{p-2}(mod \:\ p)
\]

性质2

\[C_n^mmod p\equiv C_{n\mod p}^{m\mod p}*C_{\lfloor n/p\rfloor}^{\lfloor m/p\rfloor}mod p
\]

就是一个\(a,b\)可以拆成\(P\)进制下的乘积

证明

目标方程:

\[\dbinom n m\equiv\dbinom {n\%p} {m\%p} \dbinom {n/p}{m/p}(mod p)
\]

显然右侧可以递归处理,我们只需要推左边就好

证明过程:

\[n=sp+q,m=tp+r,(q,r<p)
\]

则目标方程变成

\[\dbinom {sp+q} {tp+r} \equiv \dbinom {s} {t} \dbinom {q} {r} (mod p)
\]

下面利用二项式定理&费马小证明一个引理

\[(1+x)^n \equiv (1+x)^{ps} * (1+x)^q (mod \:\ p)
\]

\[(1+x)^n\equiv[\sum_{t=0}^p \dbinom p i x^i]^s(mod \:\ p)
\]

根据上面的那个性质

\[\equiv (1+x)^q*(1+x^p)^s(mod p)
\]

\[\equiv \sum_{i=0}^s \binom s i x^{pt} * \sum_{j=0}^q \binom q j x^j(mod p)
\]

则有

\[(1+x)^{sp+q} \equiv\sum_{i=0}^s \binom s i x^{pt} * \sum_{j=0}^q\binom q j x^j(mod p)
\]

\[\sum_{k=0}^{sp+q}\binom {sp+q} {k} x^k\equiv\sum_{i=0}^s \binom s i x^{pt} * \sum_{j=0}^q\binom q j x^j(mod p)
\]

左边\(x^{tp+r}\)的系数为\(\binom {sp+q}{tp+r}\)

右边\(x^{tp+r}\)的系数为\(\binom s t\binom q r\)

故系数相等,原命题得证

\[\dbinom {sp+q} {tp+r} \equiv \dbinom {s} {t} \dbinom {q} {r} (mod p)
\]

\[\dbinom n m\equiv\dbinom {n\%p} {m\%p} \dbinom {n/p}{m/p}(mod p)
\]

\[Lucas(n,m,p)=cm(n\%p,m\%p)*Lucas(\frac n p,\frac m p,p)
\]

\[Lucas(x,0,p) =1
\]

(以上证明结束)

实现过程

  • 目标运算结果\(C_n^m \:\ \%p\)
  • 注意输入的\(n,m\)中,可能会出现\(n\%p<m%p\),那么直接输出0即可。因为若\(n<m\),则\(C_n^m=0\)
  • 在求逆元时,运用快速幂求其\(p-2\)次方
  • 如果要大量运用\(Lucas\)定理,建议使用杨辉三角打组合数表或将阶乘以及阶乘逆元打表

Code

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define int long long
using namespace std; inline int read(){
int x = 0, w = 1;
char ch = getchar();
for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return x * w;
} int n, m, p; inline int power(int a, int b){
int ans = 1;
while(b){
if(b & 1) ans = (ans % p) * (a % p) % p;
a = (a % p) * (a % p) % p;
b >>= 1;
}
ans %= p;
return ans;
} inline int getc(int n, int m){
if(n < m) return 0;
if(m > n - m) m = n - m;
int s1 = 1, s2 = 1;
for(int i = 0; i < m; i++){
s1 = s1 * (n - i) % p;//(n-m)!/n!
s2 = s2 * (i + 1) % p;//m!
}
return s1 * power(s2, p - 2) % p;
} inline int lucas(int n, int m){
if(m == 0) return 1;
return getc(n % p, m % p) * lucas(n / p, m / p) % p;
} signed main(){
int t = read();
while(t--){
n = read(), m = read(), p = read();
cout << lucas(n + m, m) << endl;
}
return 0;
}

Lucas定理 & Catalan Number & 中国剩余定理(CRT)的更多相关文章

  1. 中国剩余定理(CRT) & 扩展中国剩余定理(ExCRT)总结

    中国剩余定理(CRT) & 扩展中国剩余定理(ExCRT)总结 标签:数学方法--数论 阅读体验:https://zybuluo.com/Junlier/note/1300035 前置浅讲 前 ...

  2. 中国剩余定理(CRT)及其扩展(EXCRT)详解

    问题背景   孙子定理是中国古代求解一次同余式方程组的方法.是数论中一个重要定理.又称中国余数定理.一元线性同余方程组问题最早可见于中国南北朝时期(公元5世纪)的数学著作<孙子算经>卷下第 ...

  3. 中国剩余定理 CRT

    中国剩余定理 CRT 正常版本CRT 要解的是一个很容易的东西 \[ \begin{aligned} x\equiv a_1(mod\ m_1)\\ x\equiv a_2(mod\ m_2)\\ . ...

  4. bzoj 3782 上学路线 卢卡斯定理 容斥 中国剩余定理 dp

    LINK:上学路线 从(0,0)走到(n,m)每次只能向上或者向右走 有K个点不能走求方案数,对P取模. \(1\leq N,M\leq 10^10 0\leq T\leq 200\) p=10000 ...

  5. 扩展GCD 中国剩余定理(CRT) 乘法逆元模版

    extend_gcd: 已知 a,b (a>=0,b>=0) 求一组解 (x,y) 使得 (x,y)满足 gcd(a,b) = ax+by 以下代码中d = gcd(a,b).顺便求出gc ...

  6. 中国剩余定理(CRT)及其拓展(ExCRT)

    中国剩余定理 CRT 推导 给定\(n\)个同余方程 \[ \left\{ \begin{aligned} x &\equiv a_1 \pmod{m_1} \\ x &\equiv ...

  7. 学习笔记:中国剩余定理(CRT)

    引入 常想起在空间里见过的一些智力题,这个题你见过吗: 一堆苹果,\(3\)个\(3\)个地取剩\(1\)个,\(5\)个\(5\)个地取剩\(1\)个,\(7\)个\(7\)个地取剩\(2\)个,苹 ...

  8. CRT中国剩余定理 & Lucas卢卡斯定理

    数论_CRT(中国剩余定理)& Lucas (卢卡斯定理) 前言 又是一脸懵逼的一天. 正文 按照道理来说,我们应该先做一个介绍. 中国剩余定理 中国剩余定理,Chinese Remainde ...

  9. [bzoj2142]礼物(扩展lucas定理+中国剩余定理)

    题意:n件礼物,送给m个人,每人的礼物数确定,求方案数. 解题关键:由于模数不是质数,所以由唯一分解定理, $\bmod  = p_1^{{k_1}}p_2^{{k_2}}......p_s^{{k_ ...

随机推荐

  1. Flink Table Api & SQL 初体验,Blink的使用

    概述 Flink具有Table API和SQL-用于统一流和批处理. Table API是用于Scala和Java的语言集成查询API,它允许以非常直观的方式组合来自关系运算符(例如选择,过滤和联接) ...

  2. 查找nginx安装目录并启动

    今天公司突然停电,来电后发现服务无法访问了,服务器是部署在公司内 发现ip ping 不通,是服务器没开 手动开了服务器,还是无法访问 可以FTP,但是不能访问服务,说明机器已经开了,有些东西应该没启 ...

  3. 流媒体学习计划表——pr

    参考教程 视频:b站oeasy 书籍:<adobe premiere pro cc 2018经典教程> 学习教训 一定要多做--实践是检验真理的唯一标准 书籍补充理论知识,视频讲究实操(理 ...

  4. JavaWeb网上图书商城完整项目--day02-19.修改密码功能流程分析

    我们来看看修改密码的业务流程操作:

  5. Python 简明教程 --- 6,Python 控制流

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io Talk is cheap, show me the code. -- Linus Torvalds ...

  6. 千金良方说:"我现在奉上179341字的MySQL资料包,还来得及吗?有"代码段、附录、和高清图!!"

    上一篇"上发布过"一不小心,我就上传了 279674 字的 MySQL 学习资料到 github 上了",我在更早之前,在微信公众号"老叶茶馆"上发布 ...

  7. Win8.1安装配置64位Oracle Database 11g的详细图文步骤记录

    在开始Oracle数据安装之前建议:1.关闭本机的病毒防火墙.2.断开互联网. 这样可以避免解压缩丢失文件和安装失败. Step1 Oracle官网下载好Windows系统64位的安装包,下载速度慢的 ...

  8. 入门大数据---Map/Reduce,Yarn是什么?

    简单概括:Map/Reduce是分布式离线处理的一个框架. Yarn是Map/Reduce中的一个资源管理器. 一.图形说明下Map/Reduce结构: 官方示意图: 另外还可以参考这个: 流程介绍: ...

  9. Mariadb之事务隔离级别

    上一篇我们聊到了mariadb的锁,以及怎么手动加锁和解锁等等,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/13196905.html:今天我们来聊一聊mar ...

  10. egret.sys.TextNode

    class Test extends egret.Shape{ protected textNode:egret.sys.TextNode; constructor(){ this.width = t ...