OI常用数学定理&方法总结
组合数计算($O(n)$)
https://www.cnblogs.com/linzhuohang/p/11548813.html
Lucas定理
如果要计算很大的组合数,但模数较小,考虑这个方法
对于质数p,$C_n^m ≡ C_{n/p}^{m/p}*C_{n \ mod \space p}^{m \ mod \space p} (mod \space p)$
这样我们可以预处理出p以内的组合数
然后不断地将n,m除以p迭代
就可以$O(p+log_p^n)$内计算很大的组合数
证明
证明来自https://www.luogu.com.cn/blog/_post/122200

代码
#include <iostream>
#include <cstdio>
using namespace std;
#define mod 10007
#define int long long
#define c(n,m) (fact[n]*ifac[m]%mod*ifac[n-m]%mod)
int fact[mod+10],ifac[mod+10];
int lucas(int n,int m)
{
if(n<m) return 0;
int s=n/mod,t=m/mod,p=n%mod,q=m%mod;
if(s==0&&t==0) return c(n,m);
return (lucas(s,t)*lucas(p,q))%mod;
}
int qpow(int a,int b)
{
int ans=1;
while(b)
{
if(b&1) ans*=a,ans%=mod;
a*=a;
a%=mod;
b>>=1;
}
return ans;
}
signed main()
{
int t;
cin>>t;
fact[0]=1;
for(int i=1;i<mod;i++) fact[i]=fact[i-1]*i%mod;
ifac[mod-1]=qpow(fact[mod-1],mod-2);
for(int i=mod-2;i>=0;i--) ifac[i]=ifac[i+1]*(i+1)%mod;
while(t--)
{
int n,m;
scanf("%lld%lld",&n,&m);
printf("%lld\n", lucas(n,m));
}
}
中国剩余定理(CRT)
这个是用来将一些要求模数为质数的方法(如上文的lucas,exgcd等)扩展成模数为任意数的方法
先将模数p拆成若干个质数$m_1*m_2...m_k$
然后逐个计算答案$a_i$
设原答案为x.
则我们其实就是要计算如下方程的解x
上述方程组有整数解。并且在模$M=\prod m_i$下的解是唯一的,解为
$(\sigma a_i*M_i*M_i^{-1})mod \ M$
其中$M_i=M/mi$,而$M_i^{-1}$为$M_i$模$m_i$的逆元。
复杂度为$O(k)$
证明
对于任意的一个i,$a_i*M_i*M_i^{-1}$
因为 $M_i*M_i^{-1} ≡ 1 (mod \space m_i)$
所以$a_i*M_i*M_i^{-1} ≡ a_i (mod \space m_i)$
对于任意一个$j!=i$
因为$M_i$中含有$m_j$
所以 $a_i*M_i*M_i^{-1}≡ 1 (mod \space m_j)$
这样全部加起来对于每一个$m_i$都能满足
代码
int prim[5]={0,3,5,6793,10007},ret[5]/*上文的ai*/,mi[5]/*上文的Mi*/,invm[5]/*上文的Mi的逆元*/;
int tot=1,ans=0,p=3*5*6793*10007;
for(int i=1;i<=4;i++) ret[i]=solve(prim[i]);
for(int i=1;i<=4;i++) mi[i]=p/prim[i],invm[i]=qpow(mi[i],prim[i]-2,prim[i]);
for(int i=1;i<=4;i++)
ans+=ret[i]*mi[i]%p*invm[i]%p,ans%=p;
printf("%lld\n", ans);
BSGS (大步小步法)
这个可以在$O(\sqrt{n})$的时间内求解最小的x满足$a^x≡b(mod \ p)\ \ gcd(a,p)=1$(限制是为了满足费马小定理的限制)
图来自https://www.cnblogs.com/SGCollin/p/9988366.html

正确性证明
因为$a^{p-1}≡ 1(mod \ p)$ (费马小定理)
所以x一定在$[0,p-2]$内
而m=$\sqrt{p}$保证了$[0,p-2]$内每一个数都能被遍历到
代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;
#define mk make_pair
#define mod 233333
#define pr pair<int,int>
#define int long long
vector<pr > vec[mod+10];
int p;
int qpow(int a,int b)
{
int ret=1;
while(b)
{
if(b&1) ret*=a,ret%=p;
a*=a;
a%=p;
b>>=1;
}
return ret;
}
bool work()
{
int b,n;
if(scanf("%lld%lld%lld",&p,&b,&n)==EOF) return false;
int m=ceil(sqrt(p));
for(int i=1;i<=m;i++)
{
int t=n*qpow(b,i)%p;
//cout<<i<<endl;
vec[t%mod].push_back(mk(t,i));
}
int ans=-1;
for(int i=1;i<=m;i++)
{
int t=qpow(b,i*m)%p;
for(int j=vec[t%mod].size()-1;j>=0;j--) if(vec[t%mod][j].first==t)
{
ans=i*m-vec[t%mod][j].second;
break;
}
if(ans!=-1) break;
}
if(ans!=-1) printf("%lld\n",ans);
else printf("no solution\n");
return true;
}
signed main()
{
while(work()) memset(vec,0,sizeof(vec));
}
矩阵-树定理
来自https://www.cnblogs.com/yangsongyi/p/10697176.html
这个定理共分为三个部分:
1.给出无向图,求这个图的生成树个数。
2.给出有向图和其中的一个点,求以这个点为根的生成外向树个数。
3.给出有向图和其中一个点,求以这个点为根的生成内向树个数。
部分一:我们对这个图构造两个矩阵,分别是这个图的连通矩阵和度数矩阵。连通矩阵S1的第i行第j列上的数字表示原无向图中编号为i和编号为j的两个点之间的边的条数。度数矩阵S2S2只有斜对角线上有数字,即只有第i行第i列上有数字,表示编号为i的点的度数是多少。我们将两个矩阵相减,即S2−S1,我们记得到的矩阵为T,我们将矩阵T去掉任意一行和一列(一般情况去掉最后一行和最后一列的写法比较多)得到T′,最后生成树的个数就是这个矩阵T′的行列式。
部分二:我们对这个图构造两个矩阵,分别是这个图的连通矩阵和度数矩阵。连通矩阵S1的第i行第j列上的数字表示原无向图中编号为i和编号为j的两个点之间编号i的点指向编号为j的点的条数。度数矩阵S2只有斜对角线上有数字,即只有第i行第i列上有数字,表示编号为i的点的入度是多少。我们将两个矩阵相减,即S2−S1,我们记得到的矩阵为T,我们将矩阵T去掉根所在行和根所在列得到T′,最后生成树的个数就是这个矩阵T′的行列式。
部分三:我们对这个图构造两个矩阵,分别是这个图的连通矩阵和度数矩阵。连通矩阵S1的第i行第j列上的数字表示原无向图中编号为i和编号为j的两个点之间编号i的点指向编号为j的点的条数。度数矩阵S2只有斜对角线上有数字,即只有第i行第i列上有数字,表示编号为ii的点的出度是多少。我们将两个矩阵相减,即S2−S1,我们记得到的矩阵为T,我们将矩阵T去掉根所在行和根所在列得到T′,最后生成树的个数就是这个矩阵T′的行列式。
证明
这个记就好了。。。
OI常用数学定理&方法总结的更多相关文章
- pandas学习(常用数学统计方法总结、读取或保存数据、缺省值和异常值处理)
pandas学习(常用数学统计方法总结.读取或保存数据.缺省值和异常值处理) 目录 常用数学统计方法总结 读取或保存数据 缺省值和异常值处理 常用数学统计方法总结 count 计算非NA值的数量 de ...
- LaTeX常用数学符号表示方法
转自:http://www.mohu.org/info/symbols/symbols.htm 常用数学符号的 LaTeX 表示方法 (以下内容主要摘自“一份不太简短的 LATEX2e 介绍”) 1. ...
- 常用数学符号的 LaTeX 表示方法
常用数学符号的 LaTeX 表示方法 (以下内容主要摘自"一份不太简短的 LATEX2e 介绍") 1.指数和下标可以用^和_后加相应字符来实现.比如: 2.平方根(square ...
- js数组及常用数学方法
数组方法 清空数组 1: arr.length=0; 2: arr=[]; arr.push() //往数组最后一个添加元素,会待会一个返回值,就是新的数组长度arr.uns ...
- JavaScript常用对象的方法和属性
---恢复内容开始--- 本文将简单介绍JavaScript中一些常用对象的属性和方法,以及几个有用的系统函数. 一.串方法 JavaScript有强大的串处理功能,有了这些串方法,才能编写出丰富多彩 ...
- LaTeX常用数学符号
之前在写博客做笔记时经常会在Word或WPS里写好数学公式再截图上传,一直觉得这样很low.现在实在是不想再去截图上传了,于是决定开始学一下LaTeX.在博客园中使用数学公式的设置可以参考在博客园使用 ...
- VB.Net常用数学函数整理
System.Math 类中定义了用于数学计算的函数.Math 类包括三角函数.对数函数和其他常用数学函数.下列函数是在 System 名称空间的 Math 类中定义的函数. 注意:要使用这些函数 ...
- Latex常用数学符号(转)
http://blog.sina.com.cn/s/blog_642075770100u0np.html Latex常用数学符号(转) 1.指数和下标可以用^和_后加相应字符来实现.比如: 2.平方根 ...
- 数学定理证明机械化的中国学派(II)
所谓"学派"是指:存在一帮人,具有同样或接近的学术观点或学术立场,採用某种特定的"方法"(或途径),在一个学术方向上共同开展工作.而且做出了相当有迎影响的学术成 ...
随机推荐
- MAVEN无法下载com.oracle:jdbc14:jar解决办法
原文链接:https://www.cnblogs.com/gqzdev/p/11742999.html 第一步,下载ojdbc14jar包: 链接:ojdbc14jar 提取码: 2m59 第二步,下 ...
- PHP 中的字符串变量
PHP 字符串变量 字符串变量用于存储并处理文本. PHP 中的字符串变量 字符串变量用于包含有字符的值. 在创建字符串之后,我们就可以对它进行操作了.您可以直接在函数中使用字符串,或者把它存储在变量 ...
- PHP ucfirst() 函数
实例 把 "hello" 的首字符转换为大写: <?phpecho ucfirst("hello world!");?> 运行实例 » 定义和用法 ...
- Skill 导出所有Layer信息用于tapeout
https://www.cnblogs.com/yeungchie/ 用于在 tapeout 前要走的流程,foundry 会需要你上传一份芯片用到的所有 Layer 的 excel 文档. TAB ...
- elasticsearch技术解析与实战ES
elasticsearch技术解析与实战ES 下载地址: https://pan.baidu.com/s/1NpPX05C0xKx_w9gBYaMJ5w 扫码下面二维码关注公众号回复100008 获取 ...
- swift demo1 tableview
代码如下: // // ViewController.swift // demo1_tableview // // Created by Alice_ss on 2018/2/24. // Copyr ...
- 如何从appstore下架自己家的app
本文主要讲如何下架appstore上边的app,我看了好多百度的,但是大部分说的都是14年左右的 ,我这边说一下最新的 1.用开发者帐号登陆到iTunes Connect 2.在iTunes Conn ...
- JVM进行篇
结合字节码指令理解Java虚拟机栈和栈帧 栈帧:每个栈帧对应一个被调用的方法,可以理解为一个方法的 ...
- 004_go语言中的常量
代码演示 package main import "fmt" import "math" const s string = "constant&quo ...
- java动态代理——代理方法的假设和验证及Proxy源码分析五
前文地址 https://www.cnblogs.com/tera/p/13419025.html 本系列文章主要是博主在学习spring aop的过程中了解到其使用了java动态代理,本着究根问底的 ...