基础
阶乘
0 ! = 1 0!=1 0!=1
组合数
a ( n , m ) = n ! ( n − m ) ! a(n,m)= \frac{n!}{(n-m)!} a(n,m)=(n−m)!n!
$c(n,m)= \frac{n!}{(n-m)!m!} $
c ( n , m ) = c ( n − 1 , m − 1 ) + c ( n , m − 1 ) c(n,m)=c(n-1,m-1)+c(n,m-1) c(n,m)=c(n−1,m−1)+c(n,m−1)
快速幂
ll qp(ll b,ll p,ll mod){
ll tmp=b,ans=1;
while(p){
if(p&1)
ans=(ans%mod*tmp%mod)%mod;
tmp=(tmp%mod*tmp%mod)%mod;
p>>=1;
}
return ans%mod;
}
快速乘
ll mil(ll a,ll b,ll p){
ll ans=0;
a%=p;
b%=p;
while(b!=0){
if(b&1){
ans+=a%p;
}
b>>=1;
a=(a<<1)%p;
}
return ans%p;
}
素数和约数
线性筛
一种非常朴素的想法:每一个筛出的质数的倍数都不是质数。
进一步:每一个筛出的质数的质数倍数都不是质数且这样算不会有遗漏。
这就是线性筛。
素数个数
一个长度为 n n n 渐进估计有 n l n ( n ) \frac{n}{ln(n)} ln(n)n 个质数
欧拉函数
读作“phi”
ϕ ( n ) \phi(n) ϕ(n) 表示 n n n 以内与 n n n 的互素的数的个数。
一些性质(筛法求的基础)
若 i i i , j j j 互质, ϕ ( i × j ) = ϕ ( i ) × ϕ ( j ) \phi(i\times j)=\phi(i)\times \phi(j) ϕ(i×j)=ϕ(i)×ϕ(j)。
若 i i i 为质数, ϕ ( i ) = i − 1 \phi(i)=i-1 ϕ(i)=i−1。
若 a a a 为质数, ϕ ( a p ) = ( a − 1 ) ∗ ϕ ( a p − 1 ) \phi(a^p)=(a-1)*\phi(a^{p-1}) ϕ(ap)=(a−1)∗ϕ(ap−1)(这个要注意)
求单个欧拉函数
基于这样一个结论( p i p_i pi 表示第 i i i 个素数),设 a = p a 1 c 1 p a 2 c 2 p a 3 c 3 . . . a=p_{a_1}^{c_1}p_{a_2}^{c_2}p_{a_3}^{c_3}... a=pa1c1pa2c2pa3c3...,则有 $\phi(a)=(1-\frac{1}{p_{a_1}}) (1-\frac{1}{p_{a_2}})… $
代码(网上贺的):
long long eular(long long n)
{
long long ans = n;
for(int i = 2; i*i <= n; i++)
{
if(n % i == 0)
{
ans -= ans/i; //等价于通项,把n乘进去
while(n % i == 0) //确保下一个i是n的素因数
n /= i;
}
}
if(n > 1)ans -= ans/n; //最后可能还剩下一个素因数没有除
return ans;
}
线性筛求欧拉函数
基于上面的结论,可得代码(还是网上贺的):
void Phi()
{
for(int i=2;i<=n;i++)
{
if(!vis[i]) prim[++pn]=i,phi[i]=i-1;
for(int j=1;j<=pn&&i*prim[j]<=n;j++)
{
vis[i*prim[j]]=1;
if(i%prim[j]==0)
{
phi[i*prim[j]]=phi[i]*prim[j];
break;
}
else phi[i*prim[j]]=phi[i]*(prim[j]-1);
}
}
}
逆元
定义
a x ax ax 和 1 1 1 关于 p p p 同余。
用于处理 a b \frac{a}{b} ba。
a b = a ∗ i n v ( b ) \frac{a}{b}=a*inv(b) ba=a∗inv(b)
费马小定理
a p − 1 a^{p-1} ap−1 和 1 1 1 关于 p p p 同余(当且仅当 p p p 为素数)。
此时 x = a p − 2 x=a^{p-2} x=ap−2 m o d mod mod p p p
递推
先贴公式(贺的),证明咕。
inv[1] = 1;
for(int i = 2; i < p; ++ i)
inv[i] = (p - p / i) * inv[p % i] % p;
想不到吧!没有证明!
整除分块
因为最近做得多所以写一下
数学分块大部分时候用于处理
∑ i = 1 n ⌊ n i ⌋ \sum_{i=1}^n \lfloor \frac{n}{i} \rfloor ∑i=1n⌊in⌋
这样类型的柿子,很多情况下藏得非常隐蔽。
r=a[i]/(a[i]/l)
矩阵
矩阵乘法
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
c[i][j]=(c[i][j]+a[i][k]*a[k][j])%mod;
}
}
矩阵快速幂
基于快速幂
#include<bits/stdc++.h>
using namespace std;
#define int long long
const long long mod=1e9+7;
long long n,k,a[105][105],ans[105][105],c[105][105];
void times1(){
memset(c,0,sizeof(c));
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
c[i][j]=(c[i][j]+ans[i][k]*a[k][j])%mod;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
ans[i][j]=c[i][j];
}
}
void times2(){
memset(c,0,sizeof(c));
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
c[i][j]=(c[i][j]+a[i][k]*a[k][j])%mod;
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
a[i][j]=c[i][j];
}
}
signed main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
//ans[i][i]=1;
for(int j=1;j<=n;j++){
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++){
ans[i][i]=1;
}
while(k){
if(k&1){
times1();
}
times2();
k>>=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout<<ans[i][j]%mod<<" ";
}
puts("");
}
return 0;
}
矩阵乘法优化DP
1)线性递推式可以构造矩阵来用快速幂优化。
2)柿子长得像矩阵乘法的(明确指出)
容斥原理
待填坑
数学期望
待填坑
一些奇怪的算法
扩展欧几里得
即俗称的 exgcd。
用于求解
a x + b y = d ax+by=d ax+by=d
这样的柿子。
我们先令 d = g c d ( a , b ) d=gcd(a,b) d=gcd(a,b)
按照 gcd 的套路推一下:
我们有 gcd ( b , a ( m o d b ) ) = gcd ( a , b ) \gcd(b,a \pmod b)=\gcd(a,b) gcd(b,a(modb))=gcd(a,b)
由此可得 a x + b y = gcd ( a , b ) = gcd ( b , a ( m o d b ) ) = b × t x + a ( m o d b ) × t y ax+by=\gcd(a,b)=\gcd(b,a \pmod b)=b \times tx+ a \pmod b \times ty ax+by=gcd(a,b)=gcd(b,a(modb))=b×tx+a(modb)×ty
按照取模的一般套路,可得 x = t y , y = t x − ⌊ a / b ⌋ × t y x=ty,y=tx-\lfloor a/b \rfloor \times ty x=ty,y=tx−⌊a/b⌋×ty
代码(贺的)
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b)
{
x=1;y=0;
return a;
}
else
{
ll tx,ty;
ll d=exgcd(b,a%b,tx,ty);
x=ty;y=tx-(a/b)*ty;
return d;
}
}
————————————————
版权声明:本文为优快云博主「zsyz_lb2003」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/zyszlb2003/article/details/89337144
欧拉定理
要不是古代猪文我都不知道有这东西
a ϕ ( m ) a^{\phi(m)} aϕ(m) 与 1 1 1 关于 m m m 同余。
前提条件: a a a 与 m m m 互质。
俺寻思费马小定理就是欧拉定理一特殊情况’
重要的是,欧拉定理可以推出一推论:
扩展欧拉定理
我不晓得,只会贺。
卢卡斯定理
不怎么常用但还是挺有用的东西
定理是这样的:
C n k m o d p = C n / p k / p C n m o d p k m o d p m o d p C_{n}^{k}\quad mod \quad p=C_{n/p}^{k/p} C_{n \quad mod \quad p}^{k \quad mod \quad p}\quad mod \quad p Cnkmodp=Cn/pk/pCnmodpkmodpmodp
写的好丑啊。
其中 p p p 必须是个质数。
代码(含 C C C 的计算方式)
inline ll comb(ll n, ll m, ll mod){
ll f1=1,f2=1;
for (ll i=1,j=n;i<=m;i++,j--){
f1=f1*j%mod;
f2=f2*i%mod;
}
return f1*qp(f2,mod-2,mod)%mod;
}
ll lucas(ll m, ll n, ll mod){
if(n==0)
return 1;
return lucas(m/mod,n/mod,mod)*comb(m%mod,n%mod,mod)%mod;
}
中国剩余定理
又叫孙子定理,用于求解一系列的模数方程组,形式化的描述戳这里(注意 CRT 的模数必须两两互质)
顺次计算每个方程,设目前算出前
k
−
1
k-1
k−1 个方程的解为
x
k
−
1
x_{k-1}
xk−1,
m
m
m 是前
k
−
1
k-1
k−1 个模数的
L
C
M
LCM
LCM,那么显然前
k
−
1
k-1
k−1 个方程的通解显然为
x
k
−
1
+
t
m
x_{k-1}+tm
xk−1+tm
。
接着考虑第 k k k 个方程,由于要满足上述条件,设 x k = x k − 1 + t m x_k=x_{k-1}+tm xk=xk−1+tm。
那么可以解方程 x k − 1 + t m ≡ a k ( m o d b k ) x_{k-1}+tm \equiv a_k \pmod {b_k} xk−1+tm≡ak(modbk)
使用 exgcd!
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[200],m[200],M=1,Mi[200],x,y,ans;
void exgcd(int a,int b){
if(b==0)
{
x=1;
y=0;
return ;
}
exgcd(b,a%b);
long long z=x;
x=y;
y=z-(a/b)*y;
}
signed main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>m[i];
M*=m[i];
cin>>a[i];
}
for(int i=1;i<=n;i++){
Mi[i]=M/m[i];
x=y=0;
exgcd(Mi[i],m[i]);
int t;
if(x<0)
t=x+m[i];
else
t=x;
ans+=a[i]*Mi[i]*t;
}
cout<<ans%M<<endl;
}