zoukankan      html  css  js  c++  java
  • OI数学 简单学习笔记

    基本上只是整理了一下框架QAQ


    PART1 数论部分

    最大公约数

    对于正整数x,y,最大的能同时整除它们的数称为最大公约数

    常用的:(lcm(x,y)=xygcd(x,y))

    裴蜀定理

    定理:对于方程(ax+by=c),其存在解的充要条件是(gcd(a,b)|c),可以拓展到n元的方程。

    证明的话应该自己yy一下还是很容易(显然可得),不过要是想要严谨证明还是去百度吧qwq

    扩展欧几里得定理

    首先我们都知道(gcd(a,b)=gcd(b,a \%b))吧。
    我们在辗转相除的同时可以递归地求出(ax+by=gcd(a,b))的解。当递归到b=0的时候,显然有解(x=1,y=0)。如果b!=0,我们可以递归的求出(bx'+(a\%b)y'=gcd(a,b))的解。

    [bx'+(a\%b)y'=bx'+(a-lfloor frac{a}{b} floor imes b)y'=ay'+b(x'-lfloorfrac{a}{b} floor y') ]

    所以(x=y',y=(x'- lfloor frac{a}{b} floor y'))
    时间复杂度:O(log n)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 100010
    using namespace std;
    int n,p;
    inline void exgcd(int a,int b,int &x,int &y)
    {
    	if(b==0) {x=1,y=0;return;}
    	else
    	{
    		int tx,ty;
    		exgcd(b,a%b,tx,ty);
    		x=ty;
    		y=tx-(a/b)*ty;
    		return;
    	}
    } 
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	scanf("%d%d",&n,&p);
    	for(int i=1;i<=n;i++)
    	{
    		int x,y;
    		exgcd(i,p,x,y);
    		while(x<0) x+=p;
    		printf("%d
    ",x);
    	}
    	return 0;
    }
    

    逆元

    定义:

    若有(xy=1pmod p),则称y为x模p意义下的乘法逆元

    计算方法:

    转换为方程:(xy-kp=1),用拓展欧几里得算法就可以了。当然费马小定理也可以,只不过时间复杂度上稍微逊色一些。(还有一种线性的,不过我不会)
    补充:费马小定理:若p为质数,对于任意(1<=a<p,a^{p-1}equiv 1 pmod p),那么在p为质数的时候(a^{p-2}就是a的逆元)
    对于费马小定理的补充:(a^bequiv a^{b\%(p-1)}pmod p)

    欧拉筛(线性筛)

    在埃氏筛法的基础上,让每个合数只被它的最小质因子筛选一次,以达到不重复的目的。
    模板:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #define MAXN 10000010
    using namespace std;
    int cnt,n,m;
    int not_prime[MAXN],prime[MAXN];
    inline void init(){
    	not_prime[1]=1;
    	for(int i=2;i<=MAXN;i++){
    		if(not_prime[i]==0){
    			prime[++cnt]=i;
    		}
    		for(int j=1;j<=cnt&&prime[j]*i<=MAXN-10;j++){
    			not_prime[prime[j]*i]=1;
    			if(i%prime[j]==0) break;
    		}
    	}
    }
    int main(){
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	scanf("%d%d",&m,&n);
    	init();
    	while(n--){
    		int a;
    		scanf("%d",&a);
    		if(not_prime[a]==0) printf("Yes
    ");
    		else printf("No
    ");
    	}
    	return 0;	
    }
    

    不过有一组性质,下面会提到(在约数个数和那里)

    积性函数

    对于任意互质整数a,b,存在(f(ab)=f(a)f(b))性质的数论函数。
    (积性函数的卷积仍然是积性函数)
    完全积性函数则是没有互质的限制。

    常见的积性函数举例:

    • φ(n) -欧拉函数
    • μ(n) -莫比乌斯函数,关于非平方数的质因子数目 (μ(n)=[k_1le1][k_2le1]...[k_mle1](-1)^m)
    • gcd(n,k) -最大公因子,当k固定的情况
    • d(n) -n的正因子数目
    • (σ_k(n)) -n的所有正因子的k次方之和(0次方的时候就是所有因子和了)(σ_k(n)=n*frac{p1-1}{p1}...frac{p_m-1}{p_m})
      积性函数都可以用线性筛筛出来

    欧拉函数

    定义:(phi(n))定义为1-n内与n互质的数的个数
    (phi(x)=xprod_1^n(1- frac{1}{p_i})),其中x是正整数,(p_i)是x的质因数。
    这个的计算程序十分好写。
    特别的,欧拉函数是积性函数,即 (phi(mn)=phi(m)phi(n))
    证明比较显然。
    这个样子是可以用线性筛,用线性的时间复杂度筛出来欧拉函数的答案——
    那么φ(1)=1,n为质数时φ(n)=n−1,最小质因子筛到它时乘上质因子p−1,否则乘上这个质数

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 110
    using namespace std;
    int cnt;
    int not_prime[MAXN],phi[MAXN],prime[MAXN];
    inline void solve()
    {
        for(int i=2;i<MAXN;i++)
        {
            if(!not_prime[i])
            {
                prime[++cnt]=i;
                phi[i]=i-1;
            }
            for(int j=1;j<=cnt&&i*prime[j]<MAXN;j++)
            {
                not_prime[i*prime[j]]=1;
                if(i%prime[j]==0)
                {
                    phi[i*prime[j]]=phi[i]*prime[j];
                    break;
                }
                else phi[i*prime[j]]=phi[i]*(prime[j]-1);
            }
        }
    }
    int main()
    {
        solve();
        for(int i=1;i<=36;i++) printf("phi[%d]=%d
    ",i,phi[i]);
        return 0;
    }
    

    线性求逆元

    在模p意义下求i的逆元:
    (p=i*x+y)
    那么(i*x+yequiv0pmod p)
    两边除以(ij)
    (x*j^{-1}+i^{-1}equiv0pmod p)
    (i^{-1}equiv-x*j^{-1}pmod p)

    [i^{-1}equiv-lfloorfrac{p}{i} floor*(p\%i)pmod p ]

    inv[1]=1;
    for(int i=2;i<=n;i++)
    	inv[i]=1ll*(p-p/i)*inv[p%i]%p;
    

    阶乘逆元的递推

    其实把最后的那个(inv[i])求出来,然后逆着一路乘上来就行了。

    约数个数的递推

    学习来源
    理论基础:
    1、对n质因数分解,(n=p1^k1 * p2^k2 * p3^k3) ……
    则n的约数个数为((k1+1)*(k2+1)*(k3+1))……
    2、线性筛素数时,用i和素数pj来筛掉 i*pj,
    其中pj一定是i*pj的最小素因子
    如果i是pj的倍数,pj也是i的最小素因子

    (t[i]) 表示i的约数个数,(e[i]) 表示i的最小素因子的个数
    A、如果i是质数,(t[i]=2,e[i]=1)
    B、如果i不是质数,枚举已有的质数(p_j)

    i*pj的最小素因子是pj

    1、如果i是pj的倍数那么e[i]即为i中包含的pj的个数,所以i*pj中包含的pj的个数为(e[i]+1)
    所以(e[i*pj]=e[i]+1,t[i*pj]=t[i]/(e[i]+1)*(e[i]+2))
    2、如果i不是pj的倍数
    (e[i*pj]=1,t[i*pj]=t[i]*t[pj])(积性函数的性质)
    (=t[i]*2)(素数的约数个数=2)

    inline void init()
    {
        memset(is_prime,1,sizeof(is_prime));
        is_prime[1]=0,mu[1]=1,d[1]=1;
        for(int i=2;i<=limit;i++)
        {
            if(is_prime[i]) prime[++cnt]=i,e[i]=1,d[i]=2,mu[i]=-1;
            for(int j=1;j<=cnt&&i*prime[j]<=limit;j++)
            {
                is_prime[i*prime[j]]=0;
                e[i*prime[j]]=1;
                if(i%prime[j]==0)
                {
                    e[i*prime[j]]+=e[i];
                    mu[i*prime[j]]=0;
                    d[i*prime[j]]=d[i]*(e[i*prime[j]]+1)/e[i*prime[j]];
                    break;
                }
                mu[i*prime[j]]=-mu[i];
                d[i*prime[j]]=d[i]*2;
            }
        }
    }
    

    线性筛约数和

    (t[i]) 表示i的约数和
    (e[i]) 表示i的约数中,不能被i的最小素因子整除的约数和

    A、i是质数,(t[i]=i+1,e[i]=1)
    B、i不是质数

    (i*pj)的最小素因子是(pj)

    1、如果i不是pj的倍数,那么i的所有约数中,必然没有pj的倍数
    可以用反证法证明这个:设x是i的约数,且x是pj的倍数,
    那么(x=pj*b,i=x*a=pj*b*a)

    即i是pj的b*a倍,与i不是pj的倍数相矛盾
    令S表示i的约数集,S’表示i的约数翻pj倍后的数的集合
    则S∩S’=∅,则S和S’中无重复元素
    所以(t[i*pj]=S+S'=t[i]+t[i]*pj=t[i]*(pj+1))
    S’中的所有元素都能整除pj,所以(e[i*pj]=t[i])

    2、如果i是pj的倍数,那么S和S’必有交集T
    T=S中pj的倍数
    所以(i*pj)的约数和要去除交集T
    那么(t[i*pj]=S+S'-T=S'+S-T=t[i]*pj+e[i])
    因为pj既是i的最小素因子,又是(i*pj)的最小素因子
    所以(e[i*pj]=e[i])

    isprime[1]=1;
    for(int i=2;i<=n;i++)
    {
    	if(!isprime[i])
    	{
    		prime[++num]=i;
    		t[i]=i+1;
    		e[i]=1;
    	}
    	for(int j=1;j<=cnt&&i*prime[j]<=n;j++)
    	{
    		isprime[i*prime[j]]=1;
    		if(i%prime[j]==0)
    		{
    			t[i*prime[j]]=t[i]*prime[j]+e[i];
    			e[i*prime[j]]=e[i];
    			break;
    		}
    		else
    		{
    			t[i*prime[j]]=t[i]*(prime[j]+1);
    			e[i*prime[j]]=t[i];
    		}
    	}
    }
    

    欧拉定理&扩展欧拉定理

    欧拉定理——需要(a,m)互质:$$a^{phi(m)}equiv1pmod m$$

    拓展欧拉定理——

    [a^bequivegin{cases}a^{b\%phi(p)}&{gcd(a,p)=1}\a^b&{gcd(a,p)=1,blephi(p)}\a^{b\%phi(p)+phi(p)}&gcd(a,p) eq1,bgephi(p)end{cases}pmod p ]

    证明请看这篇博客 戳我

    Miller-Rabin素性测试

    因为当p为质数且(1<=a<p)时,(a^{p-1}equiv 1pmod p)(欧拉定理)
    那么当(1le a<p)(a^{p-1}equiv 1pmod p)时,p是否一定是质数呢?
    当然不是啦!但是我们发现大部分合数都不满足这个性质。
    所以我们的素数判定算法出世啦!随机几个a,判断(a^{p-1}mod p)是否为1——不过这个正确性有点玄学,因为有些合数对任意的a的也都满足这个性质emmmmm,所以需要对算法进行改进。
    这样就引出了我们的二次探测定理——
    在进行Miller-rabbin算法之前,先筛去偶数,接下来只需要对奇数进行判断。
    于素数p而言,任意x=1,...,p-1,都有(x^pequiv xpmod p),而于合数,这个等式不一定成立。根据这个性质,如果找到了(1le x<n)且不满足(x^nequiv xpmod n),说明这个数n一定是合数。
    然而存在一些Carmichael数(比如说561),虽然是合数,但x取遍1,...,n-1都满足(x^nequiv pmod n)
    考虑(x^2equiv 1pmod n)的根,如果n是奇素数,只有1和n-1两根:若n是奇合数,一定存在其他的根。
    (n-1=2^r*d),其中d是奇数。若存在(0le k<r),(a^{2^k*d})不同余1或-1(mod n),但是(a^{2^{k+1}*d}equiv1 pmod n),可推断n一定是合数。
    算法时间复杂度是log的。
    加上这个玄学改进,如果我们随机的a够多,几乎就卡不掉了。随机k个判断错误的概率仅有(frac{1}{2^k})
    对于int32范围内的数,使用2,7,61探测即可。对于int64范围内的数,使用前10个素数作为探测基底即可保证算法成功。

    Pollard-Rho大整数质因数分解算法

    听说没有什么大用qwq???蒟蒻选择战略性放弃

    中国剩余定理(CRT)

    void exgcd(int a,int b,int &x,int &y)
    {
        if(b==0){ x=1; y=0; return;}
        exgcd(b,a%b,x,y);
        int tp=x;
        x=y; y=tp-a/b*y;
    }
    
    int china()
    {
        int ans=0,lcm=1,x,y;
        for(int i=1;i<=k;++i) lcm*=b[i];
        for(int i=1;i<=k;++i)
        {
            int tp=lcm/b[i];
            exgcd(tp,b[i],x,y);
            x=(x%b[i]+b[i])%b[i];//x要为最小非负整数解
            ans=(ans+tp*x*a[i])%lcm;
        }
        return (ans+lcm)%lcm;
    }
    

    exCRT

    咕咕

    BSGS

    bsgs就是哈希表(或map)+分块结合起来的优美算法。
    一般用来解决求(a^xequiv ypmod p)有解的(最小)x。

    一般我们令(x=i*m-j),(如果向别人那样写(x=i*m+j)到最后是需要exgcd的)。其中(m=sqrt p)(因为这样时间复杂度最优,总体时间复杂度即(O(sqrt p))

    然后有(a^{im-j}equiv ypmod p)

    (a^{im}equiv y*a^jpmod p)

    之后我们枚举j((jin[0,m-1])),把右边的值塞进哈希表里面(或者map也行)。

    for(int i=0,t=z;i<m;t=1ll*t*y%p,i++) M[t]=i;
    

    最后枚举i看看哈希表里有没有原先已经塞进去的值了。如果有,就输出(im-j)即可。

    for(int i=1,tt=pow(y,m),t=tt;i<m;i++,t=1ll*tt*t%p)
        if(M.count(t)) {printf("%d
    ",m*i-M[t]);flag=true;break;}
    

    一定要注意中间乘起来的时候加上*1ll!!!

    拓展BSGS

    咕咕

    斐波那契数列循环节

    咕咕

    二次剩余


    PART2 组合数学部分

    求组合数的几种方法

    • 公式法 (这个复杂度很劣)
    • 阶乘逆元求法 适用于多次查询,复杂度预处理O( n+logn ),查询接近O( 1 ),但是模数必须是质数。(100007不是质数)
      (就是先O(n)预处理阶乘,然后算出来最大数的逆元,然后倒推回来。)
    • 杨辉三角递推求法 适用于多次密集小范围查询,复杂度预处理O( n^2 ),查询O( 1 )
    • 费马小定理/exgcd求逆元 单次O( logn ),是最简单的方法,模数必须为质数
    • 阶乘分解 适用于模数不为质数的求法。复杂度预处理O( nlogn ),查询O( 1 )
    • Lucas定理(适用于处理long long级别大整数,但是模数不是很大(一般都是1e5级别)的情况)

    lucas定理

    (lucas(n,m,p)=c(n\%p,m\%p) imes lucas(n/p,m/p,p)),其中p是模数。
    (O(p))预处理之后,一次计算时间复杂度上界(O(lognlogp))

    排列组合

    这个蒟蒻我原先有过整理了,算是写了很多吧。戳我
    不过那个是在NOIP前搞的了,所以现在看来又显得简单了一些。
    所以现在特地来补充一下。

    卡特兰数

    以下内容摘抄自:这里

    卡特兰数的公式

    通项公式1:(C_n=frac{1}{n+1}C_{2n}^n=C_{2n}^n-C_{2n}^{n-1})

    通项公式2:(C_n=frac{1}{n+1}sum_{i=0}^n(C_n^i)^2)

    递推公式1:(C_{n+1}=frac{2(2n+1)}{n+2}C_n,)(C_0=1)

    递推公式2:(C_{n+1}=sum_{i=0}^{n}C_iC_{n-i-1},)(C_0)=1

    卡特兰数的应用

    • 进出栈问题
      对于一个足够大的进栈顺序为1,2,3...,n时有多少个不同的出栈序列?

    • 二叉树构成问题
      有n个节点,问总共能构成多少种不同的二叉树。
      我们可以假设,如果采用中序遍历的话,根节点第K个被访问到,则根节点的左子树有K-1个点,根节点的右子树有N-K个点,K的取值范围为1到N。

    • 凸多边形的三角划分
      一个凸的N边形,用直线连接他的两个顶点使之分成多个三角形,每条直线不能相交,问一共有多少种划分方案。
      选择一个基边,显然这是多边形划分完之后某个三角形的一条边。图中我们假设基边是p1pn,我们就可以用p1、pn和另外一个点假设为pi做一个三角形,并将多边形分成三部分,除了中间的三角形之外,一边是i边形,另一边是n-i+1边形。i的取值范围是2到n-1。所以本题的解(c(n)=c(2)*c(n-1)+c(3)*c(n-2)+...c(n-1)*c(2))。令(t(i)=c(i+2))。则(t(i)=t(0)*t(i-1)+t(1)*t(i-2)...+t(i-1)*t(0))

    • 在n*n的格子中,只在下三角行走,每次横或竖走一格,有多少中走法?其实向右走相当于进栈,向左走相当于出栈,本质就是n个数出栈次序的问题。

    • 有n+1个叶子的满二叉树的个数?事实上,向左记为+1,向右记为−1,按照向左优先的原则,从根节点开始遍历.例如第一个图记为+1,+1,+1,−1,−1,−1,于是由卡特兰数的含义可得满二叉树的个数为Cn。

    • 由n对括号组成的合法括号表达式的种类数为(C_n)

    • n+1个数连乘,不同的乘法顺序为(C_n)种。

    • 在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数?和凸包切割一个原理。

    卡特兰数的前几项:1,2,5,14,42......

    容斥

    新开了一个,详情请看这个吧


    PART3 线性代数部分

    向量

    n维向量可以看成n个数组成的n元组(或者说n个元素的数组)
    几何意义:表示n维空间中的方向和长度

    矩阵

    行列式

    一般用(|A|)或者(det(A))表示A的行列式。
    把一个n阶行列式中的元素(a_{ij})所在的第i行和第j列划去后,留下来的n-1阶行列式叫做元素(a_{ij})的余子式,记作(M_{ij})。记(A_{ij}=(-1)^{i+j}M_{ij}),叫做元素(a_{ij})的代数余子式。
    一个n×n矩阵的行列式等于其任意行(或列)的元素与对应的代数余子式乘积之和,即

    [det(A)=a_{i1}M_{i1}+...+a_{in}M_{in} ]

    以下内容参考了这篇来自candy? dalao博客

    行列式的性质:

    • (det(A)=det(A^T))
      行列式的行和列是平等的,行满足那么列也满足。
    • 令A为n×n矩阵。
      • 若A有一行或一列包含的元素全为零,则det(A)=0。
      • 若A有两行或两列相等,则det(A)=0。(因为两行互换,行列式变号)
    • 一行乘上k,行列式乘上k
      推论:行列式两行成比例或一行全0,值为0
    • 两个行列式只有一行不同,他们的行列式和等于不同的行相加后的行列式
    • 每行每列和均为0的矩阵行列式为0。
      求法:用高斯消元的方法将其化成一个上三角矩阵,然后主对角线相乘就是行列式的值。

    主子式

    n−1阶主子式,就是对于r,第r行、第r列同时去掉后得到的新行列式

    高斯消元

    解线性方程组,在概率与期望的题中作为一种解题方法还是蛮常见的。
    无解情况:化简后的有效方程组出现(0=d)型式不兼容方程,则无解 。(如下例)

    [egin{bmatrix} 1& -7& 6& | 2 \ 0& 17& -20& |-1 \ 0& 0& 0& |5 \ end{bmatrix} ]

    无穷多解情况:化简后的有效方程组个数,小于未知数个数。这样的方程组有无穷多个解。(如下例)

    [egin{bmatrix} & ext{ } 2x_{1}+3x_{2}+x_{3}=2 \ & ext{ }7x_{2}-3x_{3}=6 \ & ext{ } 0x_{1}+0x_{2}+0x_{3}=0 \ & ext{ } \ end{bmatrix} ]

    矩阵树定理

    用来解决生成树计数问题:对于一张包含N个节点的无向图,求包含N-1条边且这些边集能够构成一棵树的种类数。

    定理:G的所有不同的生成树的个数等于其基尔霍夫矩阵C[G](度数矩阵-邻接矩阵)任何一个n−1阶主子式的行列式的绝对值。

    证明:请看wzs dalao的博客 戳我
    模板题:[HEOI2015]小Z的房间

    计算几何

    这个开成专题了,详情请参考同系列学习笔记->OI计算几何 简单学习笔记


    PART4 我也不知道这是什么分类了

    范德蒙矩阵

    相关的主要就是求行列式。这个感觉百度百科上说的很详细了,也有证明,链接戳我

    点值表示

    我们可以用n个不同的(y_i=A(x_i)),用这n个点来表示一个次数界为n的多项式,称作多项式的点值表示。
    利用点值进行多项式加法和乘法只需要把(y_i)的值乘或加起来即可,时间复杂度(O(n))
    我们想到可以把系数表示转化成点值表示(求值),做乘法再转化回来(插值),就能快速计算卷积。
    点值对应唯一的多项式,证明是可以将它转化成矩阵来推,与范德蒙矩阵有关,具体证明可以看《算法导论》。

    拉格朗日插值公式

    [A(x)=sum_{i=0}^{n-1}y_ifrac{prod_{j e i}(x-x_j)}{prod_{j e i}(x_i-x_j)} ]

    欧拉公式:(e^{ix}=cosx+isinx)

    第一类斯特林数

    用n个数组成k个圆排列的方案数

    [dp[i][j]=dp[i-1][j-1]+dp[i-1][j]*(i-1) ]

    第二类斯特林数

    dp[n][m]表示n个有区别的小球,放进m个相同的盒子里,且每个盒子非空的方案数

    [dp[i][j]=dp[i-1][j-1]+dp[i-1][j]*j ]

    数论分块

    (sum i imes lfloor frac{k}{i} floor)

    for(long long l=1,r;l<=n;l=r+1)
        {
            if(k/l!=0) r=min(n,k/(k/l));
            else r=n;
            ans+=(l+r)*(r-l+1)/2*(k/l);
        }
    

    莫比乌斯反演

    其实是一种容斥。。。。
    推荐pengym dalao的博客 戳我

    二项式反演

    其实是利用的容斥定理。以下是两种常见形式。

    [f_n = sum_{i=0}^n (-1)^i {n choose i} g_i Leftrightarrow g_n = sum_{i=0}^n (-1)^i {n choose i} f_i ]

    [f_n = sum_{i=0}^n {n choose i} g_i Leftrightarrow g_n = sum_{i=0}^n (-1)^{n-i} {n choose i} f_i ]

    杜教筛

    套路式:
    现在要求的式子为(sum_{i=1}^nf(i))
    那么我们找到合适的(h,g),使得(h=g*f)
    那么根据狄利克雷卷积,我们有(h(n)=sum_{d|n}^{} g(d)f(frac{n}{d}))
    (sum_{i=1}^nh(i)=sum_{i=1}^nsum_{d|i}g(d)f(frac{n}{d}))
    我们令(s(n)=sum_{i=1}^nf(i)),之后就可以进行推导了:

    (sum_{i=1}^nh(i)=sum_{i=1}^nsum_{d|i}g(d)f(frac{n}{d}))

    (sum_{i=1}^nh(i)=sum_{d=1}^ng(d)sum_{i=1}^{lfloorfrac{n}{d} floor}f(i))(这一步不理解的话可以自己找个例子试一试帮助理解)

    (sum_{i=1}^nh(i)=sum_{d=1}^ng(d)s(lfloorfrac{n}{d} floor))

    (sum_{i=1}^nh(i)=g(1)s(n)+sum_{d=2}^ng(d)s(lfloorfrac{n}{d} floor))

    (g(1)s(n)=sum_{i=1}^nh(i)-sum_{d=2}^ng(d)s(lfloorfrac{n}{d} floor))

    当h(i)的前缀和可以很快地求出来之后(比如说时间复杂度O(1)),当我们对后面的式子进行整除分块时,求S(n)的复杂度为(O(n^{frac{2}{3}}))

    更详细的请见pengym dalao的博客 戳我

    补:yyb dalao还有几篇复习向的有关多项式的博客,写的挺好的orz


    PART5 博弈论

    Nim游戏

    结论:将每堆石子的石子个数异或起来,如果得到的结果为0,先手必败,否则先手必胜。

    证明:对于一个异或和为0的局面,由于我们进行一次操作必然会改变局面的异或和,必然不能到达异或和为0的局面。对于一个异或和不为0的局面,设现在的异或和为s,考虑异或和s二进制下最高位j,我们找到一堆石子ai,满足ai二进制下该位为1(因为异或和的性质,该堆石子必然存在),那么(ai) (xor) (s<ai),也就是说必然存在到达异或和为0的局面的操作。
    于是我们发现异或和是否大于0与先手是否必胜等价。

    游戏的和

    若局面X由若干个子游戏X1,X2,...,Xn构成,则(SG(x)=SG(X_1) xo rSG(X_2)xor...xorSG(X_n))

    SG函数

    若干个平等博弈游戏之和定义为两人轮流操作,每次操作选择一个游戏进行一次操作,不能操作者为负的平等博弈。
    对于非负整数组成的集合S,我们定义mex(s)为最小的没有在s中出现的非负整数。
    对于局面x,我们定义mex(s)为最小的没有在s中出现的非负整数。
    显然,若SG(x)>0,先手必胜,若SG(x)=0,先手必败。

    SG定理:平等博弈游戏和的SG函数等于各游戏SG函数的异或和。

    证明:
    我们只需要证明对于一个可拆分成若干个子游戏的平等博弈,若其子游戏SH异或和为x,其不能通过一次操作到达异或和为x的状态且能到达异或和为0~x-1内的每个状态。
    首先,对于一个子游戏进行操作,必然会改变其SG函数的值,异或和也必然会改变,故不能到达异或和为x的状态。
    之后再证能到达异或和为0~x-1内的每个状态,证明与Nim游戏异曲同工。

    反Nim游戏

    规定取走最后一块石子的人输(也就是轮到一个人不能操作的时候他赢)
    结论:若每对石子都只有一个石头,石子数异或和为0时先手必胜,否则石子数异或和非0时先手必胜,其他情况先手必败。
    证明:
    如果每堆石子都只有一个石头,因为奇偶性,结论显然。
    如果只有一堆大于1的石头(此时异或和一定非0),我们必然能将其变成1或者0而转到必败态。所以先手必胜。
    若不止一堆,那么操作后至少会剩一堆。那么进行几轮之后,就相当于进入了上一种局面,所以是先手必败。
    例题 [SHOI2008]小约翰的游戏john

    反博弈

    改变了一点,就是将不可操作定义为胜利。
    结论:如果任意子游戏x都满足当SG(x)=0时,x不可操作或者x一定能转移到SG函数为1的状态,那么当以下两个条件同时满足或者同时不满足的时候,先手必胜。
    1、所有子游戏的SG函数值异或和为0
    2、所有子游戏的SG函数值小于等于1


    PART6 概率与期望

    全概率公式

    把样本空间S分为若干个不相交的部分B1,B2,B3....,Bn,则(P(A)=P(A|B_1) imes P(B_1)+P(A|B_2) imes P(B_2)+...+P(A|B_n) imes P(B_n))

    数学期望

    随机变量X的数学期望EX就是所有可能值按照概率加权的和,在非正式场合中,数学期望可以被称作“在平均情况下”。

    在解决数学期望相关的题目时,可以先考虑直接使用数学期望的定义求解,计算出所有可能取值,以及对应的概率,最后加权求和。以下还有两个比较常用的性质——

    期望的线性性

    有限个随机变量之和的数学期望等于每个随机变量的数学期望之和。

    全期望公式

    类似于全概率公式,把所有情况不重复、不遗漏地分成若干类,每类计算数学期望,然后把这些数学期望按照每类的概率加权求和。


    PART7 群论

    置换

    (注:以下部分内容参考自蓝书)
    置换是把n个元素做一个全排列。比如说一般把1变成(a1),2变成(a2)...的置换记作:

    [ egin{pmatrix} 1 & 2 &... & n \ a_1 & a_2 & ... & a_n \ end{pmatrix} ]

    置换可以定义乘法,对应于函数复合。有封闭性。满足结合律,但是不满足交换律。有单位元。有逆元。
    为了处理方便,常常把置换分解成循环的乘积。而且对于任意置换,只有唯一的方法表示成不相交的循环的乘积比如说

    [egin{pmatrix} 1&2&3&4&5\ 3&5&1&4&2\ end{pmatrix} =(1;3)(2;5)(4)]

    为什么任意置换都可以这样分解?因为我们把每个元素看程一个节点,如果a变成b,连一条有向边(a o b),则每个元素恰好有一个后继节点和一个前驱节点。(就是每个点的入度和出度都为1),那么这样的图只能是若干个有向环,其中每一个环都对应一个循环。

    Burnside引理

    对于一个置换f,若一个着色方案s经过置换后不变,那么称s为f的不动点。将f的不动点数目记为(C(f)),则可以证明等价类数目为所有的(C(f))的平均值。(注意不动也是一种方案

    polya定理

    (以下内容摘自beisong dalao的博客)
    polay定理实际上是burnside引理的具体化,提供了计算不动点的具体方法。

    假设一个置换有k个循环,易知每个循环对应的所有位置颜色需一致,而任意两个循环之间选什么颜色互不影响。因此,如果有m种可选颜色,则该置换对应的不动点个数为(m^k)。用其替换burnside引理中的C(f),得到等价类数目为:

    [frac{sum_{i=0}^{|F|}m^{k_i}}{|F|}]

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


  • 相关阅读:
    mysql bin log配置及查看
    Java 相关书籍
    mysql查询性能优化
    Java线程并发:知识点
    Java 根据经纬度计算两点之间的距离
    Java加解密AES、DES、TripleDES、MD5、SHA
    Java类加载基本过程
    基本排序算法(冒泡排序 选择排序 插入排序 快速排序 归并排序 基数排序 希尔排序)
    Three.js 中的参数调试控制插件dat.GUI.JS
    Three.js中的动画实现02-[Three.js]-[Object3D属性.onAfterRender/.onBeforeRender]
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10360841.html
Copyright © 2011-2022 走看看