数学章节总结

· · 个人记录

质数

筛法

inline bool prime(int n){                     
    if(n<=2)return false;                      
    for(int i=2;i*i<=n;i++)               
        if(n%i==0)return false;                  
    return true;                      
}               

时间复杂度: O(N\sqrt{N} )

inline void primes(int n){                     
    memset(v,0,sizeof v);                 
    for(int i=2;i<=n;i++){                    
        if(v[i])continue;                     
        cout<<i<<'\n';                       
        for(int j=i;j*i<=n;j++)                 
            v[i*j]=1;                         
    }                                       
}                                           

时间复杂度: O(NloglogN)

void pri(int n){
    int m=0;
    for(int i=2;i<=n;i++){
        if(v[i]==0){
            v[i]=i;
            p[++m]=i;
        }
        for(int j=1;j<=m;j++){
            if(p[j]>v[i] || p[j]>n/i)break;
            v[i*p[j]]=p[j];
        }
    }
}

时间复杂度:O(N)

质因数分解

任何一个大于1的整数都能唯一分解为有限个质数的乘积可写作:

N=p_1^{C1} p_2^{C2} p_3^{C3}···p_m^{Cm}

所以结合试除法与埃氏筛法,我们可以扫描2到\sqrt N 的每一个数d,若d能整除N,则从N中除掉所有因子d,同时累计除去的d的个数。

void divide(int n){
    m=0;
    for(int i=2;i*i<=n){
        if(n%i==0){
            p[++m]=i;
            c[m]=0;
            while(n%i==0)n/=i,c[m]++;
        }
    }
    if(n>1)
        p[++m]=n,c[m]=1;
    for(int i=1;i<=m;i++)
        cout<<p[i]<<'^'<<c[i]<<'\n';    
} 

约数

约数基本定理

一个大于1的整数的正约数集合可以记作:

\quad\left\{p_{1}^{b_{1}} p_{2}^{b_{2}} \ldots p_{m}^{b_{m}}\right\} \text{其中}0 \leqslant b_{i} \leqslant c_{i}

其正约数个数可以记作:

\prod_{i=1}^{m}\left(C_{i}+1\right)

即每个C_i+1的乘积

其正约数之和可以记作:

\quad\left(1+p_{1}+p_{1}^{2}+\cdots+p_{1}^{c_{1}}\right) \cdots\left(1+p_{m}^{1}+p_{m}^{2}+\cdots+p_{m}^{cm}\right)=\prod_{i=1}^{m}\left(\sum_{j=0}^{c_{i}}\left(p_{i}\right)^{j}\right)

阶乘中因子出现的次数有

\left\lfloor\frac{n}{x}\right\rfloor+\left\lfloor\frac{n}{x^{2}}\right\rfloor+\left\lfloor\frac{n}{x^{3}}\right\rfloor+\ldots+\left\lfloor\frac{n}{x^{m}}\right\rfloor \text { 次。 }

(约数个数)代码:

#include<bits/stdc++.h>
using namespace std;
int n,sum;
int v[1000005];
int main(){
    cin>>n;
    for(int i=1;i<=n;i++) for(int j=1;i*j<=n;j++)   v[i*j]++;   //当改成v[i*j]+=i时就是求约数和   
    for(int i=1;i<=n;i++)cout<<v[i]<<"\n";
    return 0;
} 

最大公约数

附:__gcd(int,int)是一个好用的函数(用于求int与int之间的最大公约数)

定义

最大公约数:对于一个数x,使它既为a的约数,也为b的约数,并使x尽可能地大。则x就是a,b的最大公约数
最小公倍数:对于一个数x,使它既为a的倍数,也为b的倍数,并使x尽可能地小。则x就是a,b的最小公倍数

性质(最大公约数)

设x为a,b的最大公约数,则有x \mid ax \mid b,所以x \mid a-b

求解方法

由性质可以得出gcd(a,b)=gcd(b,a - b )(a>b) 。所以易得gcd(a,b)=gcd(b,a\bmod b)

code:

int gcd(int a,int b){
    if(b==0) return a;
    return gcd(b,a%b);
}

欧拉函数

欧拉函数的定义 n 中与 n 互质的数的个数称为欧拉函数,记为 \varphi(n) 例: \varphi(1)=1, \varphi(2)=1, \varphi(3)=2, \varphi(4)=2, \varphi(5)=4

欧拉函数的性质 1.若 p 是质数,则 \varphi(\mathrm{p})=\mathrm{p}-1 2.若 p 是质数,则 \varphi\left(\mathrm{p}^{\mathrm{k}}\right)=(\mathrm{p}-1) \mathrm{p}^{\mathrm{k}-1} 3.积性函数:若 \operatorname{gcd}(\mathrm{m}, \mathrm{n})=1 ,则 \varphi(\mathrm{mn})=\varphi(\mathrm{m}) \varphi(\mathrm{n}) N=p_{1}^{c_{1}} p_{2}^{c_{2}} \ldots p_{m}^{c_{m}} \varphi(N)=N \times\left(1-\frac{1}{p_{1}}\right)\left(1-\frac{1}{p_{2}}\right) \ldots\left(1-\frac{1}{p_{m}}\right)

费马小定理

设p是素数。对于任意整数a且p \nmid a,都成立a^p ≡ a (mod p)

欧拉定理

若正整数 \mathrm{a}, \mathrm{n} 互质,则 a^{\varphi(n)} \equiv 1(\bmod n) ,其中 \varphi(\mathrm{n}) 为欧拉函数

扩展欧拉定理

若正整数 n 为质数,则对于任意整数 a 有 a^{n} \equiv a(\bmod n)

若正整数 \mathrm{a}, \mathrm{n} 互质,对于任意正整数 b ,则 a^{b} \equiv a^{b \bmod \varphi(n)}(\bmod n)

b=q \times \varphi(n)+r \\ r=b \bmod \varphi(n) \end{array} a^{b} \equiv a^{q \times \varphi(n)+r} \equiv\left(\underline{a}^{\varphi(\mathrm{n})}\right)^{q} \times a^{r} \equiv 1^{q} \times a^{r} \equiv a^{r} \equiv a^{b \bmod \varphi(n)}(\bmod \mathrm{n})

a^{b} \equiv a^{b \bmod \varphi(n)+\varphi(n)}(\bmod n)

裴蜀定理(又称贝祖定理)

定义

对于任意整数a,b,一定存在整数x,y满足ax+by=gcd(a,b)

则二元整数线性不定方程 ax+by=c 有解当且仅当gcd(a,b) \mid c

裴蜀定理求不定方程

问题:求 a x+b y=g c e l(a, b)- 组整数解
当 b=0 时 a x+b y=a ,故而 x=1, y=0
b \neq 0 时由欧几里得算法, \operatorname{gcd}(a, b)=\operatorname{gcd}(b, a \% b)
由裴蜀定理 \operatorname{gcd}(a, b)=a x+b y

\operatorname{gcdl}(b, a \% b)=b x_{1}+(a \% b) y_{1} \\\\ \quad=b x_{1}+\left(a-\left\lfloor\frac{a}{b}\right\rfloor \times b\right) y_{1} \\\\ \quad=a y_{1}+b\left(x_{1}-\frac{a}{b} y_{1}\right) \end{array} \text { 所以, } {x=y_{1}, y=x_{1}-\frac{a}{b} y_{1}} \text {. }

可以用递归算法,先求出下一层的 \mathrm{x} 1, \mathrm{y} 1 再回代到上一层,层层回代,可求特解 \left(\mathrm{x}_{0}, \mathrm{y}_{0}\right) 构造通解

x=x_{0}+\frac{b}{\operatorname{gcd}(a, b)} \times k \\\\ y=y_{0}+\frac{a}{\operatorname{gcdl}(a, b)} \times k \end{array}

矩阵

定义

一个 n m 的矩阵可看作一个 n m 的二维数组。矩阵的加法和减法就是把两个矩阵对应位置上的数相加减,即 C=A \pm B \Leftrightarrow \forall i \in[1, n], \forall j \in[1, m], C_{i, j}=A_{i, j} \pm B_{i, j} ,其中 A, B, C 都是 n * m 矩阵。

矩阵乘法

$~~~~$矩阵乘法满足结合律,即 $ (A * B) * C=A *(B * C) $ ,满足分配律,即 (A+B) * C= A * C+B * C ,不满足交换律,即 A * B 不一定等于 B * A 。 $~~~~$考虑矩阵乘法中一种特殊的情形, F 是 1 * n 矩阵, A 是 n * n 矩阵,则 $ F^{\prime}=F * A $ 也是 $1 * n $ 矩阵。 F 和 $ F^{\prime} $ 可看作一维数组,省略它们的行下标 1。按照矩阵乘法的定义,$ \forall j \in[1, n] $ ,有 $ F_{j}^{\prime}=\sum_{k=1}^{n} F_{k} * A_{k, j} $ 。它的含义是,经过一次与 A 的矩阵乘法运算后, F 数组中的第 k 个值会以 $ A_{k, j} $ 为系数累加到 F^{\prime} 数组的第 j 个值上,等价于在一个向量的 k, j 两个状态之间发生了递推。 ```cpp #include<bits/stdc++.h> #define int long long using namespace std; const int M=1e4; int n,k; struct matrict{ int a[5][5]; matrict(){ memset(a,0,sizeof a); } }; matrict operator *(matrict A,matrict B){ matrict c; for(int i=1;i<=2;i++){ for(int j=1;j<=2;j++){ for(int x=1;x<=2;x++){ c.a[i][j]=(c.a[i][j]+A.a[i][x]*B.a[x][j])%M; } } } return c; } signed main(){ while(cin>>n && n!=-1){ if(n==0 || n==1){ cout<<n<<'\n'; continue; } matrict a,ans; a.a[1][1]=a.a[1][2]=a.a[2][1]=1; for(int i=1;i<=2;i++){ ans.a[i][i]=1; } int k=n-2; while(k){ if(k&1)ans=ans*a; a=a*a; k>>=1; } cout<<(ans.a[1][1]+ans.a[1][2])%M<<'\n'; } return 0; } ``` #### 单位矩阵 定义:对角线为1,其余部分为0的n*n的矩阵叫做单位矩阵。 性质:任意能与他相乘的矩阵与他相乘后都会回到本身。 ### 高斯消元 #### 定义 消元法是将方程组中的一方程的未知数用含有另一未知数的代数式表示,并将其带入到另一方程中,这就消去了一未知数,得到一解;或将方程组中的一方程倍乘某个常数加到另外一方程中去,也可达到消去一未知数的目的。消元法主要用于二元一次方程组的求解。 而高斯消元核心在于: - 两方程互换,解不变; - 一方程乘以非零数 𝑘![k](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7),解不变; - 一方程乘以数 𝑘![k](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 加上另一方程,解不变。 #### 高斯消元的过程可以分为以下几步: 1. 增广矩阵行初等行变换为行最简形; 2. 还原线性方程组; 3. 求解第一个变量; 4. 补充自由未知量; 5. 列表示方程组通解。 ```cpp #include <bits/stdc++.h> using namespace std; int n; double a[100][100]; double eps=1e-4; bool gauss(){ for(int i=1;i<=n;i++){ for(int k=i;k<=n;k++)if(fabs(a[k][i])>eps){swap(a[k],a[i]);break;} if(fabs(a[i][i])<eps)return 0; for(int j=n+1;j>=i;j--)a[i][j]/=a[i][i]; for(int k=i+1;k<=n;k++){ for(int j=n+1;j>=i;j--){ a[k][j]-=a[k][i]*a[i][j]; } } } for(int i=n-1;i>=1;i--){ for(int j=i+1;j<=n;j++) a[i][n+1]-=a[i][j]*a[j][n+1]; } return 1; } int main(){ cin>>n; for(int i=1;i<=n;i++){ for(int j=1;j<=n+1;j++){ cin>>a[i][j]; } } if(gauss()){ for(int i=1;i<=n;i++)printf("%.2lf\n",a[i][n+1]); } else cout<<"No Solution"; return 0; } ``` ### 矩阵求逆 矩阵求逆,即求矩阵的逆矩阵。矩阵是线性代数的主要内容,很多实际问题用矩阵的思想去解既简单又快捷。逆矩阵又是矩阵理论的很重要的内容,逆矩阵的求法自然也就成为线性代数研究的主要内容之一。 设A是数域上的一个n阶方阵,若在相同数域上存在另一个n阶矩B,使得: AB=BA=E。 则我们称B是A的逆矩阵,而A则被称为可逆矩阵。其中,E为单位矩阵。 典型的矩阵求逆方法有:利用定义求逆矩阵、初等变换法、伴随阵法、恒等变形法等。 ```cpp #include <bits/stdc++.h> #define int long long using namespace std; const int M=1e9+7; int n; int a[405][810]; int ksm(int a,int b){ int ans=1; while(b){ if(b&1)ans=ans*a%M; a=a*a%M; b>>=1; } return ans; } bool gauss(){ for(int i=1;i<=n;i++){ for(int k=i;k<=n;k++)if(a[k][i]){swap(a[k],a[i]);break;} if(!a[i][i])return 0; int kk=ksm(a[i][i],M-2); for(int j=1;j<=n;j++){ if(j==i)continue; int p=a[j][i]*kk%M; for(int k=i;k<=n<<1;k++){ a[j][k]=((a[j][k]-p*a[i][k])%M+M)%M; } } for(int j=1;j<=n<<1;j++) a[i][j]=a[i][j]*kk%M; } for(int i=1;i<=n;i++){ for(int j=n+1;j<n<<1;j++) printf("%lld ",a[i][j]); printf("%lld\n",a[i][n<<1]); } return 1; } signed main(){ ios::sync_with_stdio(0); cin.tie(0); cin>>n; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ cin>>a[i][j];a[i][i+n]=1; } } if(!gauss()) cout<<"No Solution"; return 0; } ``` # 组合计数基础 #### 在组合计算方案数时有两种基本原理: - 加法原理 $\ \ $ 完成一件事的方法有 n 类,其中第 i 类方法包括 $a_{i}$ 种不同的方法,且这些方法互不重合,则完成这件事共有 $a_{1}+a_{2}+\cdots+a_{n} $ 种不同的方法。 - 乘法原理$~~~~$若完成一件事需要 n 个步骤,其中第 i 个步骤有 $ a_{i} $ 种不同的完成方法,且这些步骤互不干扰,则完成这件事共有 $a_{1} * a_{2} * \cdots * a_{n} $ 种不同的方法。 #### 在组合计数中有组合与排列两种方式: - 排列:$ A_n^m $是组合的数学表示,意思是从n个中选m个出来进行排列。$ ~A_n^m= \frac {n!}{(n-m)!}=n *(n-1) * \cdots * (n-m+1) $。之所以$ A_n^m $它能够表达排列的意思,是因为在选出来的m个位置中,第一个有n种选法,第二个有n-1种选法......以此类推,第m个就有n-m+1种选法,再用乘法原理将它们相乘就是排列。 - 组合:$ C_n^m $是排列的数学表示,意思是从n个中选m个但不进行排列(不考虑顺序)。$~ C_{n}^{m}=\frac{n!}{m!(n-m)!}=\frac{n *(n-1) * \cdots *(n-m+1)}{m *(m-1) * \cdots * 2 * 1} $。之所以$ C_n^m $它能够表达组合的意思,是因为在排列中,有多种所选数字相同,但顺序不同的区别,所以会有重复项,将重负部分除掉即可(就是m!)。 #### 性质 - $ C_{n}^{m}=C_{n}^{n-m}

证明:

组合数的求法

code:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
int p;
int a,b;
int f[N],g[N];
int ksm(int a,int b){
    int c=1;
    while(b){
        if(b&1)c=c*a%p;
        a=a*a%p;
        b>>=1;
    }
    return c;
}
int ask(int n,int m,int p){
    int mb=1,ma=1;
    for(int i=1;i<=m;i++)mb=mb*i%p;
    for(int i=n-m+1;i<=n;i++)ma=ma*i%p;
    return ma*ksm(mb,p-2)%p;
}
signed main(){
    int T;cin>>T;
    while(T--){
        cin>>a>>b>>p;
        cout<<ask(a,b,p)<<'\n';
    }
    return 0;
}

二项式定理

(a+b)^{n}=\sum_{k=0}^{n} C_{n}^{k} a^{k} b^{n-k}

证明:

数学归纳法。当 n=1 时, (a+b)^{1}=C_{n}^{0} a^{0} b^{1}+C_{n}^{1} a^{1} b^{0}=a+b 成立。 假设当 n=m 时命题成立,当 n=m+1 时:

(a+b)^{m+1}=(a+b)(a+b)^{m}=(a+b) \sum_{k=0}^{m} C_{m}^{k} a^{k} b^{m-k} \\\\ =\sum_{k=0}^{m} C_{m}^{k} a^{k+1} b^{m-k}+\sum_{k=0}^{m} C_{m}^{k} a^{k} b^{m-k+1}=\sum_{k=1}^{m+1} C_{m}^{k-1} a^{k} b^{m-k+1}+\sum_{k=0}^{m} C_{m}^{k} a^{k} b^{m-k+1} \\\\ =\sum_{k=0}^{m+1}\left(C_{m}^{k-1}+C_{m}^{k}\right) a^{k} b^{m-k+1}=\sum_{k=0}^{m+1} C_{m+1}^{k} a^{k} b^{m+1-k} \end{array}

Lucas 定理

对于素数 p ,有

其中,当 n<k 时,二项式系数 $\binom{n}{k}$ 规定为 0 。 Lucas 定理指出,模数为素数 𝑝![p](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 时,大组合数的计算可以转化为规模更小的组合数的计算。在右式中,第一个组合数可以继续递归,直到 𝑛,𝑘 <𝑝![n,k<p](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 为止;第二个组合数则可以直接计算,或者提前预处理出来。写成代码的形式就是: ```cpp long long Lucas(long long n, long long k, long long p) { if (k == 0) return 1; return (C(n % p, k % p, p) * Lucas(n / p, k / p, p)) % p; } ``` ### 卡特兰数 Catalan 数经常出现在各类计数问题中。比利时数学家 在 1958 年研究括号序列计数问题时发现了这一数列,它也因此得名。 Catalan 数满足如下递推关系: $C_{n}=\left\{\begin{array}{ll} 1, & n=0 \\ \sum_{i=0}^{n-1} C_{i} C_{n-1-i}, & n>0 \end{array}\right.

数列的前几项为:

1,1,2,5,14,42,132,429,1430, \ldots

常见形式

Catalan 数有如下常见的表达式:

C_{n}=\frac{1}{n+1}\binom{2 n}{n}=\frac{(2 n)!}{n!(n+1)!}, n \geq 0 \\ C_{n}=\binom{2 n}{n}-\binom{2 n}{n+1}, n \geq 0 \\ C_{n}=\frac{(4 n-2)}{n+1} C_{n-1}, n>0, C_{0}=1\\ \end{array}

Catalan 数的这些形式都可以高效计算:前两个形式将它转换为阶乘和组合数的计算问题,第三个形式则提供了顺次计算的递推公式。

容斥与莫比乌斯函数及概率期望

容斥原理

在计数时,必须注意没有重复,没有遗漏。为了使重叠部分不被重复计算,人们研究出一种新的计数方法,这种方法的基本思想是:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理。
如果被计数的事物有A、B、C三类,那么,A类和B类和C类元素个数总和= A类元素个数+ B类元素个数+C类元素个数—既是A类又是B类的元素个数—既是A类又是C类的元素个数—既是B类又是C类的元素个数+既是A类又是B类而且是C类的元素个数。(A∪B∪C = A+B+C - A∩B - B∩C - C∩A + A∩B∩C)

\begin{array}{l} \left|A_{1} \cup A_{2} \cup \cdots \cup A_{m}\right|= \\ \sum_{1 \leq i \leq m}\left|A_{i}\right|-\sum_{1 \leq i<j \leq m}\left|A_{i} \cap A_{j}\right|+\sum_{1 \leq i<j<k \leq m}\left|A_{i} \cap A_{j} \cap A_{k}\right|-\cdots+(-1)^{m-1}\left|A_{1} \cap A_{2} \cap \cdots \cap A_{m}\right| \end{array}

也可表示为 设 S 为有限集, A_{i} \subseteq S(i=1,2, \cdots, n, n \geq 2) ,则

\left|\bigcup_{i=1}^{n} A_{i}\right|=\sum_{k=1}^{n}(-1)^{k-1} \sum_{1<i_{1}<i_{2}<\cdots<i_{k}<n}\left|A_{i_{1}} \cap A_{i_{2}} \cap \cdots \cap A_{i_{k}}\right|

由于

\begin{array}{l} \overline{A_{1} \bigcup A_{2} \bigcup \ldots \bigcup A_{n}}=\overline{A_{1}} \bigcap \overline{A_{2}} \bigcap \cdots \bigcap \overline{A_{n}} \\ \overline{A_{1} \bigcap A_{2} \bigcap \cdots \bigcap A_{n}}=\overline{A_{1}} \bigcup \overline{A_{2}} \bigcup \ldots \bigcup \overline{A_{n}} \end{array}

所以

\left|\overline{A_{1}} \bigcap \overline{A_{2}} \bigcap \cdots \bigcap \overline{A_{n}}\right|=N-\left|A_{1} \bigcup A_{2} \bigcup \ldots \bigcup A_{n}\right|

两个集合的容斥关系公式: A \cup B=|A \cup B|=|A|+|B|-|A \cap B|

\text { 三个集合的容斥关系公式: }|\mathrm{A} \cup \mathrm{~B} \cup \mathrm{C}|=|\mathrm{A}|+|\mathrm{B}|+|\mathrm{C}|-|\mathrm{A} \cap \mathrm{~B}|-|\mathrm{B} \cap \mathrm{C}|-|\mathrm{C} \cap \mathrm{~A}|+ |\mathrm{A} \cap \mathrm{B} \cap \mathrm{C}|

莫比乌斯函数

莫比乌斯函数是指以下的函数:

1 & \text { 若 } n=1 ; ~ \\ (-1)^{k} & \text { 若 } n \text { 无平方数因数, 且 } n=p_{1} p_{2} \ldots \ldots p_{k} ; \\ 0 & \text { 若 } n \text { 有大于 } 1 \text { 的平方数因数。 } \end{array}\right.

莫比乌斯函数完整定义的通俗表达:
1)莫比乌斯函数μ(n)的定义域是N;
2)μ(1)=1;
3)当n存在平方因子时,μ(n)=0;
4)当n是素数或奇数个不同素数之积时,μ(n)=-1;
5)当n是偶数个不同素数之积时,μ(n)=1。

性质1 莫比乌斯函数是一个数论函数,它是一个积性函数。

\sum_{d \mid n} \mu(d)=\left\{\begin{array}{ll} 1 & (n=1) \\ 0 & (n>1) \end{array}\right.

通俗地讲,当 N 包含相等的质因子时, \mu(N)=0

N 的所有质因子各不相等时:

N 有偶数个质因子, \mu(N)=1

N 有奇数个质因子, \mu(N)=-1

证明:
(1)当 n=1 时显然
(2)当 \mathrm{n} \neq 0 时,将 n 分解可以得到 n=p_{1}^{a_{1}} p_{2}^{a_{2}} \ldots p_{k}^{a_{k}} 在 n 的所有因子中, \mu 值不为零的只有所有质因子次数都为 1 的因子,其中质因数个数为 r 个的因子有 C_{k}^{r} 个那么显然有:

\sum_{d \mid n} \mu(d)=C_{k}^{0}-C_{K}^{1}+C_{k}^{2}+\ldots+(-1)^{k} C_{k}^{k}=\sum_{i=0}^{k}(-1)^{i} C_{k}^{i}

性质2
对任意正整数 n 有:

\sum_{d \mid n} \frac{\mu(d)}{d}=\frac{\varphi(n)}{n}
int pri[N],vis[N],sum[N],mo[N];
void init(){
    mo[1]=1;
    for(int i=2;i<N;i++){
        if(!vis[i]){
            pri[++cnt]=i;
            mo[i]=-1;
        }
        for(int j=1;i*pri[j]<N;j++){
            vis[i*pri[j]]=1;
            if(i%pri[j]==0)break;
            mo[i*pri[j]]=mo[i]*-1;
        }
    }
    for(int i=1;i<N;i++)sum[i]=mo[i]+sum[i-1];
}

概率期望

在概率论和统计学中,期望值是指在一个随机变量试验中每次可能结果的概率乘以其结果的总和。换句话说,期望值是随机试验在同样的机会下重复多次的结果计算出的等同“期望”的平均值。需要注意的是,期望值并不一定等同于常识中的“期望”——“期望值”也许与每一个结果都不相等。

定义

若随机变量 X 的取值有 x_{1}, x_{2}, \cdots ,一个随机事件可表示为 X=X_{i} ,其概率为 P\left(X=X_{i}\right)=p_{i} ,则称 E(X)=\sum p_{i} x_{i} 为随机变量 X 的数学期望。通俗地讲,数学期望是随机变量取值与概率的乘积之和。

例如在掷两枚骰子的点数实验中,样本空间是由 36 个样本点构成的集合,每个样本点可写作 (a, b) ,其中 1 \leq a ; b \leq 6 。随机变量有多种,不妨以"掷出的点数之和 X "为例,则随机变量 X 的取值为 2 \sim 12 。随机事件可描述为"掷出 X 点",即由 a+b=X 的样本点 (a, b) 构成的子集。掷出 8 点的概率 P(X=8)=5 / 36 。掷出的点数的数学期望为:

\frac{1}{36} *(2+12)+\frac{1}{18} *(3+11)+\frac{1}{12} *(4+10)+\frac{1}{9} *(5+9)+\frac{5}{36} *(6+8)+\frac{1}{6} * 7=7

性质

因为期望是线性的,所以有:

E(aX=bY)=a*E(X)+B*E(Y)

博弈论

博弈论(game theory)是经济学的一个分支,主要研究具有竞争或对抗性质的个体,在特定规则下所产生的各种行为。博弈论关注博弈中个体的预期行为与实际行为,并研究其最优策略。

通俗地讲,博弈论主要研究的是:在一个游戏中,进行游戏的多位玩家如何选择策略。

合作/非合作博弈

合作博弈(cooperative game)是指参与者可以结成联盟、相互合作的博弈。在这类博弈中,个体的不合作行为往往会受到某种外部机制的惩罚。与之相对,非合作博弈中并不存在这样的机制,因此,参与者要么无法结成联盟,要么只能依赖可信的威胁机制维持合作。

相比合作博弈,非合作博弈的研究更为系统和成熟。

对称/非对称博弈

对称博弈中,不同参与者在做出相同行为时获得的收益是相同的,也就是说,收益只取决于行为本身,而与行为者的身份无关。不满足这一条件的博弈称为 非对称博弈

零和/非零和博弈

零和博弈指的是无论各方采取何种行为,所有参与者的收益总和始终为零。通常讨论的零和博弈涉及两名参与者,此时,一方的收益必然是另一方的损失。相对地,非零和博弈允许多方共赢或共输,包括 正和博弈负和博弈等。

公平组合博弈

公平组合游戏中,最基础也最重要的是正常 Nim 游戏。Sprague–Grundy 定理指出,所有正常规则的公平组合游戏都等价于一个单堆 Nim 游戏。由此,可以发展出 Sprague–Grundy 函数和 Nim 数的概念,它们完全地刻画了一个正常规则的公平组合游戏。

Nim 游戏

共有 n 堆石子,第 i堆有 a_i 枚石子。两名玩家轮流取走任意一堆中的任意多枚石子,但不能不取。取走最后一枚石子的玩家获胜。

Nim 游戏中,局面可能的变化可以用博弈图来描述。

将每一个可能的状态都看作是图中的一个结点,并将状态向它的后继状态(即通过一次操作可以达到的状态)连边,就得到一个有向无环图,这就是博弈图。图是无环的,因为 Nim 游戏中,每次操作,石子的总数量都是严格减少的。

由于 Nim 游戏是公平组合游戏,每个玩家是否有必胜策略,只取决当前游戏所处的状态,而与玩家的身份无关。因此,所有状态可以分为(先手)必胜状态 和(先手)必败状态

所有公平组合游戏中,博弈图都是有向无环图。所以,通过这三条性质,可以在绘制出博弈图后,在 𝑂(|𝑉| +|𝐸|)的时间内,计算出每个状态是必胜状态还是必败状态。其中,|𝑉|为博弈图的状态数目,|𝐸|为边数,即所有状态可以采取的行动的数量的总和。

通过绘制博弈图,可以在 Ω(∏𝑛𝑖=1𝑎𝑖)的时间内求出某一局面是否是先手必胜。但是,这样做的复杂度过高,无法实际应用。实际上,可以发现 Nim 游戏的状态是否先手必胜,只与当前局面的石子数目的 Nim 和有关。

Nim 游戏中,状态 (𝑎_1,𝑎_2,⋯,𝑎_𝑛) 是必败状态 P,当且仅当 Nim 和𝑎_1⊕𝑎_2⊕⋯⊕𝑎_𝑛=0.

由此,可以在 𝑂(𝑛) 时间内判断 Nim 游戏的一个状态是否为先手必胜状态。

证明

对所有可能的状态应用归纳法:

  1. 如果 𝑎_i =0对所有 𝑖 =1,⋯,𝑛都成立,该状态没有后继状态,且 Nim 和等于 0,命题成立。

  2. 如果 𝑘 =𝑎_1 ⊕𝑎_2 ⊕⋯ ⊕𝑎_𝑛 ≠0,那么,需要证明该状态是必胜状态。也就是说,需要构造一个合法移动,使得后继状态为必败状态;由归纳假设,只需要证明后继状态满足 𝑎′_1 ⊕𝑎′_2 ⊕⋯ ⊕𝑎′_𝑛 =0。利用 Nim 和(即异或)的性质,这等价于说,存在一堆石子,将 𝑎𝑖拿走若干颗石子,可以得到 𝑎_𝑖 ⊕𝑘,亦即 𝑎_𝑖 >𝑎_𝑖 ⊕𝑘

    实际上,设 𝑘 的二进制表示中,最高位的 1 是第 𝑑 位。那么,一定存在某个 𝑎_𝑖,使得它的二进制第 𝑑 位是 1。对于相应的石子堆,就一定有 𝑎_𝑖>𝑎_𝑖 ⊕𝑘,因为 𝑎_𝑖 ⊕𝑘中第 𝑑 位为 0,更高位和 𝑎_𝑖! 一样。

  3. 如果 𝑎_1 ⊕𝑎_2 ⊕⋯ ⊕𝑎_𝑛 =0,那么,需要证明该状态是必败状态。由归纳假设可知,只要证明它的所有后继状态的 Nim 和都不是 0。这是必然的,任何合法移动将 𝑎_𝑖变为 𝑎′_𝑖 ≠𝑎_i,就必然会使得 Nim 和变为 𝑎′_𝑖 ⊕𝑎_𝑖 ≠0!