组合数计算($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常用数学定理&方法总结的更多相关文章

  1. pandas学习(常用数学统计方法总结、读取或保存数据、缺省值和异常值处理)

    pandas学习(常用数学统计方法总结.读取或保存数据.缺省值和异常值处理) 目录 常用数学统计方法总结 读取或保存数据 缺省值和异常值处理 常用数学统计方法总结 count 计算非NA值的数量 de ...

  2. LaTeX常用数学符号表示方法

    转自:http://www.mohu.org/info/symbols/symbols.htm 常用数学符号的 LaTeX 表示方法 (以下内容主要摘自“一份不太简短的 LATEX2e 介绍”) 1. ...

  3. 常用数学符号的 LaTeX 表示方法

    常用数学符号的 LaTeX 表示方法 (以下内容主要摘自"一份不太简短的 LATEX2e 介绍") 1.指数和下标可以用^和_后加相应字符来实现.比如: 2.平方根(square ...

  4. js数组及常用数学方法

    数组方法 清空数组   1: arr.length=0;   2: arr=[]; arr.push()          //往数组最后一个添加元素,会待会一个返回值,就是新的数组长度arr.uns ...

  5. JavaScript常用对象的方法和属性

    ---恢复内容开始--- 本文将简单介绍JavaScript中一些常用对象的属性和方法,以及几个有用的系统函数. 一.串方法 JavaScript有强大的串处理功能,有了这些串方法,才能编写出丰富多彩 ...

  6. LaTeX常用数学符号

    之前在写博客做笔记时经常会在Word或WPS里写好数学公式再截图上传,一直觉得这样很low.现在实在是不想再去截图上传了,于是决定开始学一下LaTeX.在博客园中使用数学公式的设置可以参考在博客园使用 ...

  7. VB.Net常用数学函数整理

      System.Math 类中定义了用于数学计算的函数.Math 类包括三角函数.对数函数和其他常用数学函数.下列函数是在 System 名称空间的 Math 类中定义的函数. 注意:要使用这些函数 ...

  8. Latex常用数学符号(转)

    http://blog.sina.com.cn/s/blog_642075770100u0np.html Latex常用数学符号(转) 1.指数和下标可以用^和_后加相应字符来实现.比如: 2.平方根 ...

  9. 数学定理证明机械化的中国学派(II)

    所谓"学派"是指:存在一帮人,具有同样或接近的学术观点或学术立场,採用某种特定的"方法"(或途径),在一个学术方向上共同开展工作.而且做出了相当有迎影响的学术成 ...

随机推荐

  1. Django学习路3

    1.打开 Data Source alt insert 打开 Data Source 找到 db.sqlite3 确定 Download 下载后 TestConnection 测试是否成功 2.项目下 ...

  2. WPF 半透明 模糊效果 Aero效果(1)

    先看看效果图 目前网上找到了2种实现方式,一种是 .NET Framework4.5及以后有自带的 WindowChrome 效果,一种是 WindowsAPI  dwmapi.dll  ,但这两种在 ...

  3. PHP array_diff() 函数

    实例 比较两个数组的值,并返回差集: <?php $a1=array("a"=>"red","b"=>"gree ...

  4. PDOStatement::debugDumpParams

    PDOStatement::debugDumpParams — 打印一条 SQL 预处理命令(PHP 5 >= 5.1.0, PECL pdo >= 0.9.0) 说明 语法 bool P ...

  5. PDOStatement::fetchObject

    PDOStatement::fetchObject — 获取下一行并作为一个对象返回.(PHP 5 >= 5.1.0, PECL pdo >= 0.2.4)高佣联盟 www.cgewang ...

  6. python3.4嵌套循环项目:买房分期付款(1)

    #案例:买房分期付款24万(10年期限) i=1#定义年份sum1=0while i<=10: print("第",i,"年到了......") j=1# ...

  7. 利用 Python 写一个颜值测试小工具

    我们知道现在有一些利用照片来测试颜值的网站或软件,其实使用 Python 就可以实现这一功能,本文我们使用 Python 来写一个颜值测试小工具. 很多人学习python,不知道从何学起.很多人学习p ...

  8. IdentityServer4 (4) 静默刷新(Implicit)

    写在前面 1.源码(.Net Core 2.2) git地址:https://github.com/yizhaoxian/CoreIdentityServer4Demo.git 2.相关章节 2.1. ...

  9. Unity 笔记

    摄像机 Main Camera 跟随主角移动,不看 UI 剧情摄像机 当进入剧情时,可以关闭 main camera,启用剧情摄像机,不看 UI UI 摄像机 看 UI Unity编辑器常用的sett ...

  10. 8、Builder 建造者模式 组装复杂的实例 创造型模式

    1.什么是Builder模式 定义: 将一个复杂对象的构建与表示相分离,使得同样的构建过程可以创建不同的表示.大白话就是,你不需要知道这个类的内部是什么样的,只用把想使用的参数传进去就可以了,达到了解 ...