数学公式/定理/板子整理

1.各种数

  全排列:P(n,n)=n!    部分排列P(n,m)=n!/(n-m)!

  组合数:公式:C(n,m)=n!/(m!*(n-m)!)   递推式 :C(n,m)=C(n-1,m)+C(n-1,m-1)  

      Lucas定理:C(n,m)%p=C(n/p,m/p)*C(n%p,m%p)%p

      
#define long long LL 
//farc[i]表示i! 
LL C(LL n,LL m,LL p){
    if(n<m)return 0;
    return farc[n]*fpow(farc[m],p-2,p)%p*fpow(farc[n-m],p-2,p)%p;
}
LL Lucas(LL n,LL m,LL p){
    if(n<m)return 0;
    if(!n)return 1;
    return Lucas(n/p,m/p,p)*C(n%p,m%p,p)%p;
}
Lucas

      性质/应用:1.C(n,m)=C(n,n-m)

            2.二项式定理:

            3.m*C(n,m)=n*C(n-1,m-1)

            4.C(n,1)²+C(n,2)²+C(n,3)²+...+C(n,n)²=C(2n,n)

  圆排列: Q(n,n)=(n-1)!   n个人坐成一圈有多少种坐法。

       Q(n,m)=P(n,m)/m=n!/(m*(n-m)!)   部分圆排列  

  重复排列(有限个):n!/(a1!*a2!*…*ak!)  k种不一样的球,每种球的个数分别是a1,a2,...ak,设n=a1+a2+…+ak,求这n个球的全排列数。

  重复组合(无限个):  C(n+k-1,k)      n种不一样的球,每种球的个数是无限的,从中选k个出来的方案数。

  不相邻组合:C(n-k+1,k)  1~n这n个自然数中选k个,这k个数中任何两个数不相邻数的组合有多少种。

  错排(错位排列):d(n)=(n-1)*(dn-1 + dn-2),n≥3

  stirling数: 第一类:S(n,m)=S(n-1,m-1)+(n-1)*S(n-1,m)    n个不同元素构成m个圆排列的方案数

       第二类:S(n,m)=S(n-1,m-1)+m*S(n-1,m).       n个不同元素构成m个非空的(无差别)集合的方案数

  Catalan数:通项式:H(n)=C(2n,n)/(n+1)=(2n)!/( (n+1)!*n!)

             Hn=C(2n,n)-C(2n,n-1)

         递推式:

  部分转载自https://www.cnblogs.com/ljc20020730/p/11302718.html   

        https://blog.csdn.net/qq_36808030/article/details/75045129 

2.数论:       阶:

             原根:

           常见的数的原根: 998244353:3       1e9+7:5       19260817:15 

  部分转载自:https://www.cnblogs.com/zwfymqz/p/8244902.html#_label2_6

2.群论:       轨道稳定子定理:设G是[1,n]上的一个置换群,Ek是[1,n]在G的作用下包含k的等价类,Zk是k不动置换类。有|Ek||Zk|=|G|.

           拉格朗日定理:设H是有限群G的子群,则H的阶整除G的阶

           Burnside引理:对于一个置换f,若一个染色方案s经过置换后不变,称s为f的不动点。将f的不动点数目记为C(f),则可以证明等价类数目为所有C(f)的平均值。

                  

           polya引理:假设一个置换有k个循环,易知每个循环对应的所有位置颜色需一致,而任意两个循环之间选什么颜色互不影响。

                  因此,如果有m种可选颜色,则该置换对应的不动点个数为m^k。用其替换burnside引理中的C(f),得到等价类数目为:

                  

                  其中|F|表示置换的数目,ki表示第i个置换包含的循环个数  

          一些群论好题:polya引理模板 burnside引理好题 polya好题

  部分转载自: https://www.cnblogs.com/beisong/p/4767858.html  

3.线性代数:

  1.矩阵:

    加减乘除快速幂模板

struct mat {
  long long ma[sz][sz];
  mat() { memset(ma, 0, sizeof ma); }
}a,b,c;
mat operator+(const mat &A,const mat &B){
    mat res;
    for (int i = 0; i < sz; ++i)
      for (int j = 0; j < sz; ++j)
        res.ma[i][j] = (A.ma[i][j] + B.ma[i][j] + p) % p;
    return res;
}
mat operator-(const mat &A,mat &B) {
    mat res;
    for (int i = 0; i < sz; ++i)
      for (int j = 0; j < sz; ++j) res.ma[i][j] = (A.ma[i][j] - B.ma[i][j]) % p;
    return res;
}
mat operator*(mat &A,mat &B) {
    mat res;
    for (int i = 0; i < sz; ++i)
        for (int j = 0; j < sz; ++j)
            for (int k = 0; k < sz; ++k)
                res.ma[i][j] = (res.ma[i][j] + A.ma[i][k] * B.ma[k][j]) % p;
    return res;
}
mat operator^(mat &A,long long &x){
    mat res, bas;
    for (int i = 0; i < sz; ++i) res.ma[i][i] = 1;
    for (int i = 0; i < sz; ++i)
      for (int j = 0; j < sz; ++j) bas.ma[i][j] = A.ma[i][j];
    while (x) {
      if (x & 1) res = res * bas;
      bas = bas * bas;
      x >>= 1;
    }
    return res;
}
MATRIX

  2.向量/复数:

struct Complex
{
    double x,y;
    Complex(){}
    Complex(double _x,double _y)
    {
        x=_x;
        y=_y;
    }
};
Complex operator +(const Complex &a,const Complex &b)
{
    return Complex(a.x+b.x,a.y+b.y);
}
Complex operator -(const Complex &a,const Complex &b)
{
    return Complex(a.x-b.x,a.y-b.y);
}
Complex operator *(const Complex &a,const Complex &b)
{
    return Complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);
}
Complex

    单位根:在代数中,若zn=1,我们把z称为n次单位根

        在复平面上,以原点为圆心,1为半径作圆,所得的圆叫单位圆。以圆点为起点,圆的n等分点为终点,做n个向量,设幅角为正且最小的向量对应的复数为ωn,称为n次单位根。

        性质:1.  2.   

  部分转载自:https://www.cnblogs.com/zwfymqz/p/8244902.html#_label2_6

4.多项式:

  多项式的一些性质:1.卷积:系数表达:ci=∑ij=0 aj*bi-j    点值表达:ci=ai*bi   

  FFT板子:

#include<bits/stdc++.h>
using namespace std;
const double Pi = acos(-1.0);
const int MAXN = 1e7 + 7;
int n, m, limit = 1, r[MAXN], L, l, N, M;
inline int read(){
    int res = 0, f = 1;
    char c = getchar();
    while(c < '0' || c > '9'){if(c == '-')f = -1; c = getchar();}
    while(c >= '0' && c <= '9'){res = res * 10 + c - '0', c = getchar();}
    return res * f;
}
struct Complex{
    double x, y;
    Complex (double xx = 0, double yy = 0) {x = xx, y = yy;}
} a[MAXN], b[MAXN];
Complex operator + (Complex a, Complex b){return Complex(a.x + b.x, a.y + b.y);}
Complex operator - (Complex a, Complex b){return Complex(a.x - b.x, a.y - b.y);}
Complex operator * (Complex a, Complex b){return Complex(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);}
void FFT (Complex *A, int type){
    for(int i = 0; i < limit; i++){
        if(i < r[i])swap(A[i], A[r[i]]);
    }
    for(int mid = 1; mid < limit; mid <<= 1){
        Complex WN = Complex (cos(Pi / mid), type * sin(Pi / mid));
        for(int len = mid << 1, l = 0; l < limit; l += len){
            Complex W = Complex (1, 0);
            for(int k = 0; k < mid; k++, W = W * WN){
                Complex x = A[l + k], y = W * A[l + k + mid];
                A[l + k] = x + y;
                A[l + k+ mid] = x - y;
            }
        }
    }
}
int main() {
    n = read();
    m = read();
    for(int i = 0; i <= n; i++){
        a[i].x = read();
    }
    for(int i = 0; i <= m; i++){
        b[i].x = read();
    }
    while(limit <= n + m){
        limit <<= 1;
        L++;
    }
    for(int i = 0; i < limit; i++){
        r[i] = (r[i >> 1] >> 1) | ((i & 1) << (L - 1)); 
    }
    FFT(a, 1);
    FFT(b, 1);
    for(int i = 0; i <= limit; i++){
        a[i] = a[i] * b[i];
    }
    FFT(a, -1);
    for(int i = 0; i <= n + m; i++){
        printf("%d ", (int)(a[i].x / limit + 0.5));
    }
} 
FFT
#include <bits/stdc++.h>
using namespace std;
const double Pi=acos(-1);
const int MAX_N=1<<21;
struct Complex
{
    double x,y;
    Complex(){}
    Complex(double _x,double _y)
    {
        x=_x;
        y=_y;
    }
};
Complex operator +(const Complex &a,const Complex &b)
{
    return Complex(a.x+b.x,a.y+b.y);
}
Complex operator -(const Complex &a,const Complex &b)
{
    return Complex(a.x-b.x,a.y-b.y);
}
Complex operator *(const Complex &a,const Complex &b)
{
    return Complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);
}
Complex A[MAX_N],B[MAX_N],C[MAX_N];
int n,m; 
int ans[MAX_N],r[MAX_N],limit=1,L; 
void FFT(Complex A[],int flag)
{
    for(int i=0;i<limit;i++)
    {
        if(r[i]>i)swap(A[i],A[r[i]]);
    }
    for(int mid = 1; mid < limit; mid <<= 1){
        Complex WN = Complex (cos(Pi / mid), flag * sin(Pi / mid));
        for(int len = mid << 1, l = 0; l < limit; l += len){
            Complex W = Complex (1, 0);
            for(int k = 0; k < mid; k++, W = W * WN){
                Complex x = A[l + k], y = W * A[l + k + mid];
                A[l + k] = x + y;
                A[l + k+ mid] = x - y;
            }
        }
    }
    if(flag==-1)for(int i=0;i<limit;i++)A[i].x/=limit;
}
int main()
{
    string s1,s2;
    cin>>s1>>s2;
    int n=s1.size()-1,m=s2.size()-1;
    for(int i=0;i<=n;i++)A[i].x=s1[n-i]-'0';
    for(int i=0;i<=m;i++)B[i].x=s2[m-i]-'0';
    while(limit <= n + m){
        limit <<= 1;
        L++;
    }
    for(int i = 0; i < limit; i++){
        r[i] = (r[i >> 1] >> 1) | ((i & 1) << (L - 1)); 
    }
    FFT(A,1);
    FFT(B,1);
    for(int i=0;i<limit;i++)C[i]=A[i]*B[i];
    FFT(C,-1);
    for(int i=0;i<=n+m;i++)ans[i]=(int)(C[i].x+0.5);
    for(int i=0;i<=n+m;i++)
    {
        ans[i+1]+=ans[i]/10;
        ans[i]%=10;
    }
    for(int i=n+m+(ans[n+m+1]!=0);i>=0;i--)cout<<ans[i];
    cout<<endl;
    return 0;
}
FFT高精乘

    NTT板子:

#include<bits/stdc++.h>
using namespace std;
const int p=998244353;
const int D=3;
const int inD=332748118;
long long a[10000100],b[10000100],c[10000010];
int r[10000010];
int n,m,L;
inline int read(){
    char c=getchar();int f=1,res=0;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){res=res*10+c-'0';c=getchar();}
    return f*res;
}
long long pw(long long a,long long b){
    long long res=1;
    while(b){
        if(b&1)res=res*a%p;
        a=a*a%p;
        b>>=1;
    }
    return res;
}
int limit=1;
void NTT(long long *A,int type){
    for(int i=0;i<limit;i++){
        if(i<r[i])swap(A[i],A[r[i]]);
    }
    for(int mid=1;mid<limit;mid<<=1){
        long long WN=pw((type==1?D:inD), (p-1)/(mid<<1));
        for(int l=0;l<limit;l+=(mid<<1)){
            long long W=1;
            for(int k=0;k<mid;k++,W=(W*WN)%p){
                long long x=A[l+k],y=(W*A[l+k+mid])%p;
                A[l+k]=(x+y)%p;
                A[l+k+mid]=(x-y+p)%p;
            }
        }
    }
    if(type==-1){
        long long inv=pw(limit, p-2);
        for(int i=0;i<limit;i++){
            A[i]=A[i]*inv%p;
        }
    }
}
int main(){
    n=read();
    m=read();
    for(int i=0;i<=n;i++){
        a[i]=read();
    }
    for(int i=0;i<=m;i++){
        b[i]=read();
    }
    while(limit<=n+m){
        limit<<=1;
        L++;
    }
    for(int i=0;i<limit;i++){
        r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
    }
    NTT(a,1);
    NTT(b,1);
    for(int i=0;i<limit;i++){
        c[i]=(a[i]*b[i])%p;
    }
    NTT(c,-1);
    for(int i=0;i<=n+m;i++){
        printf("%lld ",c[i]);
    }
}
NTT

5.其他:

  约瑟夫问题: 假设编号从0开始   F(i)表示在有i个人参与下 报数为m时 最后获胜的玩家编号 f[1]=0 ,f[i]=(f[i-1]+m) % i ,(i>1)

         报数为2时 J(g)表示g个人参与下最终获胜的人的编号   g=2**t+x (2t>x  x0则 J(g)=2x+1​     2**t为不超过g的最大的二次幂

        一些约瑟夫问题的好题罗德岛裁员

   

原文地址:https://www.cnblogs.com/passione-123456/p/11915235.html