中国剩余定理
//模板
int exgcd(int a,int b,int &x,int &y) //扩展欧几里得算法 c = ax + by gcd(a,b)|c
{
if(b==0)
{
x=1;
y=0;
return a;
}
int d = exgcd(b,a%b,y,x);
y -= a/b*x;
return d;
}
int ChineseRemainder(int a[],int w[],int len) // a[]存放余数 w[]存放两两互质的数
{
int x,y,m,n=1,ret=0;
for (int i=0; i<len; i++)
n *= w[i];
for (int i=0; i<len; i++)
{
m = n/w[i];
int d = exgcd(w[i],m,x,y);
ret = (ret+y*m*a[i])%n;
}
return (n+ret%n)%n;
}
快速幂取模
long long PowMod(long long a,long long n,long long m) // a^n%m
{
long long res = 1;
while( n!=0 )
{
if (n&1)
res = res * a % m;
a =a*a%m;
n = n>>1;
}
return res;
}
欧拉函数
对正整数n,欧拉函数表示小于n的正整数中与n互质的数的数目 φ(1)=1
const int N = 1000005;
int phi[N];
vector<int> prime;
void init() //欧拉函数筛 O(n) + O(1)
int main()
{
phi[1] = 1;
for(int i=2; i<N; i++)
{
if(phi[i] == 0)
{
prime.push_back(i);
phi[i] = i-1;
}
for(int j=0; j<prime.size() && prime[j]*i<N; j++)
{
if(i%prime[j] == 0)
{
phi[i*prime[j]] = phi[i] * prime[j];
break;
}
else
phi[i*prime[j]] = phi[i] * (prime[j]-1);
}
}
}
费马小定理
组合数
C(n,m) = n! / ( (n-m)! * m! )(n>=m)
long long Cnm(int n, int m)// n个中取m个
{
if (m == 0)
return 1;
long long up = 1;
long long down = 1;
for (int i=0; i<m; i++)
{
up *= (n - i);
down *= (i + 1);
}
return up / down;
}
全错位排序
一个人写了n封不同的信及相应的n个不同的信封,他把这n封信都装错了信封,问都装错信封的装法有多少种?
由递推公式得
long long f[30];
void init()
{
for(int i=2; i<=25; i++)
{
if(i & 1)
f[i] = i * f[i-1] - 1;
else
f[i] = i * f[i-1] + 1;
}
}
第一类斯特林数
把一个包含n个元素的集合分成k个环排列的方法数。
假设已经推出了n-1个元素分成k个环的方法数以及n-1个元素分成k-1个环的元素,我们考虑第n个元素,一种情况是这个元素自己成环,于是是S(n-1,k-1),另一种情况是把这个元素放到任意一个元素的左边,方案数是(n-1)S(n-1,k).
初始值
S[n][0] = 0, S[1][1] = 1;
递推公式
S[n][k] = S(n-1,k-1) + (n-1)S(n-1,k)
long long stir[maxn][maxn];
void init()
{
stir[1][1] = 1;
for(int i=2; i<maxn; i++)
for(int j=1;j<=i; j++)
stir[i][j] = stir[i-1][j-1] + (i-1) *stir[i-1][j];
}
第二类斯特林数
把一个包含n个元素的集合分成k个非空子集的方法数。
考虑第n个元素,如果它自成一个集合,那么前n-1个元素构成k-1个集合,就是S(n,k),如果它不是自成集合,那么前面n-1个元素构成k个集合,再把第n个元素加到任意一个集合中,共k种方案。
初始值 S[n][0]=0, S[n][k]=0 (n
Lucas
C(n,m)%p=C(n/p,m/p) * C(n%p,m%p) % p p为素数
long long fac[maxn];
void init(long long mod)
{
fac[0] = 1;
for(int i=1; i<=mod; i++)
fac[i] = fac[i-1] * i % mod;
}
long long lucas(long long n, long long m, long long p)
{
long long ret = 1;
while(n && m)
{
long long a = n%p;
long long b = m%p;
if(a < b)
return 0;
ret = (ret * fac[a] * PowMod(fac[b]*fac[a-b]%p, p-2, p)) %p;
n /= p;
m /= p;
}
return ret;
}