• 【算法】数学


    【数论】数论——onion_cyc

    【计数问题】计数问题(排列组合,容斥原理,卡特兰数)——onion_cyc

    【概率与期望】链接

    【链与反链】链接

    【生成树计数(矩阵树定理)】专题链接

    【快速幂】

    原理:将指数化为二进制再分为若干个数相乘。

    每次自己乘自己相当于平方,增加二进制权。

    int quickpow(int x,int k)
    {
        int ans=1;
        while(k>0){
            if(k&1)ans=1ll*ans*x%MOD;
            k>>=1;
            x=1ll*x*x%MOD;
        }
        return ans;
    }
    View Code

    【矩阵快速幂】

    应用范围:1.图的矩阵。2.优化递推。

    矩阵运算的意义在于把一切加法,乘法,乘幂的递推全部转化为独立的乘法,这样就可以用线段树或矩阵快速幂等维护。

    特点:1.整体矩阵的规则变换。2.数据范围通常是10^18。

    引用自:矩阵快速幂总结 by wust_wenhao

    矩阵十题(3) by jumping_frog

    对于矩阵A和B,矩阵乘法运算定义为:

    $$C(i,j)=sum_{k=1}^{n}A(i,k)*B(k,j)$$

    为了方便,这里只讨论行列相等的方阵。

    更广泛的,可以对矩阵乘法重定义运算$oplus$和$otimes$,则有:

    $$C(i,j)=sum_{oplus}(i,k) otimes  B(k,j)$$

    注意,运算必须满足分配律,即:$aotimes (boplus c)=(aotimes b) oplus (a otimes c)$

    矩阵乘法常用于优化常系数线性递推式,数据范围通常10^18,复杂度为O(N^3*log n),其中N为方阵边长。

    矩阵乘法满足分配律,不满足交换律

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int n=2,MOD=10000;
    int a[n][n],b[n][n],t[n][n],m;
    void mul(int a[n][n],int b[n][n],int ans[n][n])
    {
        for(int i=0;i<n;i++)
         for(int j=0;j<n;j++)
          {
              t[i][j]=0;
              for(int k=0;k<n;k++)
               t[i][j]=(t[i][j]+a[i][k]*b[k][j])%MOD;
          }
        for(int i=0;i<n;i++)
         for(int j=0;j<n;j++)
          ans[i][j]=t[i][j];
    }
    int main()
    {
        scanf("%d",&m);
        while(m!=-1)
         {
             if(m==0){printf("0
    ");scanf("%d",&m);continue;}
            m--;
             a[0][0]=a[0][1]=a[1][0]=1;a[1][1]=0;
             b[0][0]=1;b[1][0]=b[0][1]=b[1][1]=0;
             while(m>0)
              {
                  if(m&1)mul(a,b,b);
                  m>>=1;
                  mul(a,a,a);
              }
             printf("%d
    ",b[0][0]);
             scanf("%d",&m);
         }
        return 0;
    }
    View Code

    例题:【POJ】3070 Fibonacci

    ★矩阵乘法的第一种形式:图的矩阵(信息记载在整个矩阵上)

    这类矩阵乘法通常定义$C^x$的意义(一般是走恰好x步),然后通过$C^{x-1}$递推得来。

    例1:无向图i到j走x步的路径数

    定义图的邻接矩阵$A$,走x步的答案矩阵$C^x$,通过枚举中转点k:

    $$C^x(i,j)=sum_{k=1}^{n}C^{x-1}(i,k)*A(k,j)$$

    这恰好是矩阵乘法的形式,故$ans=A^x(i,j)$。

    注意A(i,i)=0,否则就是<=x步。

    初始单位矩阵只要考虑实际意义(走0步)即可得ans(i,i)=1。

    例题:【BZOJ】1875: [SDOI2009]HH去散步 矩阵快速幂

    例2:无向图i到j走x步的最短路

    定义图的邻接边权矩阵$A$,无边为inf,通过枚举中转点k:

    $$C^x(i,j)=min_k{C^{x-1}(i,k)+A(k,j)}$$

    重定义运算,容易发现满足分配律(a+min{b,c}=min{a+b,a+c}),故$ans=A^x(i,j)$。

    A(i,i)=inf,ans(i,i)=0。

    例题:【BZOJ】1706: [usaco2007 Nov]relays 奶牛接力跑 

    【BZOJ】1297: [SCOI2009]迷路 拆点后是上题

    【BZOJ】2165: 大楼 倍增

    【CodeForces】576 D. Flights for Regular Customers 倍增

    第二类矩阵乘法:优化常系数递推方程(信息记载在列向量上)

    通法:构造列向量A和转移矩阵T,使得$T imes A^n=A^{n+1}$,从而有$T^n imes A^0=A^n$,然后就可以对T^n进行矩阵快速幂。

    或者,$T^k imes A^n=A^{n+k}$

    列向量中可能需要一些没有出现的未知数方便构造转移矩阵,目的是要计算出f[i]的同时将其它项转移成为A[i]。

    eg. f[i]=f[i-1]+f[i-2]+f[i-4]

    (我是图>w<)

    为什么多个f[i-3]?因为f[i-4]->f[i-3]的转移需要f[i-3]的存在。

    例题:【bzoj】2326 [HNOI2011]数学作业

    【POJ】3233 Matrix Power Series 经典题:二分序列求递增幂。

    套路:

    1.加法的常数进列向量,乘法的常数进转移矩阵,n在幂把底数的幂进列向量,转移乘底数

    4.矩阵和式化递推

    5.★非递推式矩乘:少量固定的元素,固定的变化规则(不存在决策),一次变化是一次转移,求最终状态。

    6.需要使用同列元素更新时,考虑同列元素的更新来源,从上一列拿。

    7.二维DP数组可以直接将第二维视为列向量,二维常数数组直接作为转移矩阵的参考。

    8.二项式可以将展开项放进列向量方便转移。(hdu)

    bzoj4417》矩乘只能优化从前一两项递推过来的,所以可以通过记录前缀和等强行化成递推式,矩乘优化

    bzoj1898》转移矩阵的变化以12为周期,那么将12个不同的转移矩阵处理相乘,就可以快速幂计算k/12了,然后暴力计算k%12就可以了。矩乘变化非常灵活。

    bzoj4870题解,居然是考虑答案的实际组合意义是%k=r(因为k和r都很小),然后f[i][j]表示前i件物品取后%k=j的方案数……然后随便递推矩乘就可以了QAQ。

    bzoj5118》求Fib(2^n),n<=10^5,%大素数。

    由欧拉定理,$A^{2^n-1} mod p =A^{2^n-1 mod p-1} mod p$,然后就没了……

    《bzoj2004》【BZOJ】2004: [Hnoi2010]Bus 公交线路 动态规划+矩阵快速幂

    状态压缩,将状态作为元素矩乘。

    【高斯消元】gauss

    小结:高斯消元

    标准过程

    1.一个n行n列的系数方程组,n+1列为答案。

    2.对于第i行,第i列为主元,找到同列最大主元并交换。【这里记得比较绝对值!!!

    3.用第i行减倍消去下面行的第i列元。

    4.回代:对于第i行,非主元直接取值减去,除以主元系数得到i元存在a[i][n+1]。

    void gauss()
    {
        int r;
        for(int i=1;i<=n;i++)
         {
             r=i;
             for(int j=i+1;j<=n;j++)
              if(fabs(a[j][i])>fabs(a[r][i]))r=j;
             if(r!=i)for(int j=1;j<=n+1;j++)swap(a[r][j],a[i][j]);
             for(int k=i+1;k<=n;k++)
              for(int j=n+1;j>=i;j--)
               a[k][j]-=a[k][i]/a[i][i]*a[i][j];      
         }
        for(int i=n;i>=1;i--)
         {
             for(int j=i+1;j<=n;j++)
              a[i][n+1]-=a[j][n+1]*a[i][j];
             a[i][n+1]/=a[i][i];
         }
    }
    gauss

    自由元问题

    对于第i列,如果从i~n行找不到一个系数不为0的a[j][i]来当主元素,说明该列为自由元

    自由元的选择不一定,但自由元的个数一定

    有自由元的话回代没有意义,应该在确定自由元后再回代

    方程无解或有无限解问题

    (那些左边全0的方程就不能再贡献非0系数了,这些方程要么恒成立要么矛盾。)

    重要类型——异或方程组

    选择主元只须1。

    消元只消去系数为1的行,整行对应异或。

    主元系数为1,回代。

    void gauss()//保证有解 
    {
        int r;
        for(int i=1;i<=n;i++)
         {
             for(int j=i;j<=n;j++)if(a[j][i]){r=j;break;}
             if(r!=i)for(int j=1;j<=n+1;j++)swap(a[i][j],a[r][j]);
             for(int j=i+1;j<=n;j++)if(a[j][i])
              for(int k=i;k<=n+1;k++)
               a[j][k]^=a[i][k];
         }
        for(int i=n;i>=1;i--)
         for(int j=i+1;j<=n;j++)
          if(a[i][j])a[i][n+1]^=a[j][n+1];
    }
    异或方程组

    常与期望概率题目结合,列出n个式子(循环调用)后解方程

    【异或】异或的性质及运用

    1.异或就是不进位加法(当然是对于某一位来说)。

    2.满足结合律,而且可以拿到等式右边,不变号。

    3.满足自反性,即A^A=0,可以用于消去元素。

    找多余数:利用自反性,全部异或和-异或和。

    相同的数字,奇数个异或得原数,偶数个异或得0。

    4.与0异或不变,与1异或取反

    【线性基】解决相互异或的值域问题

    参考:[学习笔记]线性基 byYveh

    构造:对数字集合a[i]构造线性基数组b[i],每个数字从高位到低位枚举。假设当前为第x位,如果b[x]存在数字那么异或b[x],否则将当前值赋给b[x]。(b[x]存的是线性基中最高位的1在第x位的数字)

    for(int i=1;i<=n;i++)
    {
        for(int j=62;j>=0;j--)if(a[i]&(1<<j))
        {
            if(!b[j]){b[j]=a[i];break;}
            else a[i]^=b[j];
        }
    }
    View Code

    特点

    1.线性基中的数字2^m种组合的异或和的值域,和原数字集合互相异或的非零值域一致。(原数字集合值域可能存在0)

    2.线性基中的数字互相异或的值不为0。

    3.大小为m的线性基在数字集合中有m个依赖数字(构造时赋值的数字),这m个数字可以直接构成线性基(因为相互异或是等价的)。

    故线性基是原数字集合中,最大的值域不含0的子集。

    应用

    1.判断异或为0子序列的存在:若有数字无须加入线性基则根据自反性存在。

    使序列不存在子序列异或和为0:去除除了线性基依赖数字外的其他数字,则构造不出0。

    2.最大异或值:从高位到低位扫描线性基,对答案有贡献则异或。

    3.最小异或值:即最低位线性基

    4.第k小值:首先定义“关键位”为线性基中m个数字的最高位,改造线性基使得每个数字的所有关键位只有最高位是1。

    具体方法只要枚举每个数字的每个关键位,如果是1就异或对应的值。

    这样之后,当最终数字的关键位的01排列确定后,数字也就唯一确定了(因为选择的组合唯一确定)。

    那么第k小值就是 [ k的二进制对应的01组合 ] 作为 [ 线性基数字的选择 ] 得到的数字。

    例题:

    1.【BZOJ】3105: [cqoi2013]新Nim游戏[bzoj 2460]线性基+贪心+证明过程

    给定序列,求最大权 [ 值域不含0 ] 的子集。

    贪心,从大到小排序后加入线性基。这样是对的……证明见第二个链接。

    2.

    【博弈论】

    引用自:博弈问题及SG函数

    博弈相关论文(只是贴一贴):张一飞博弈 浅谈SG游戏的若干拓展及变形 解析一类组合游戏

    <Nim>

    N-position 先手必胜局面

    P-position 先手必败局面

    1.无法进行任何移动的局面(terminal position)是P-position。

    2.可以移动到P-position的局面是N-position。  先手必胜,采用正确的决策就能到达先手必败。

    3.所有移动都导致N-position的局面是P-position。  先手必败,无论怎么走都只能到达先手必胜。

    特别地,(0,0)是P-position,(x,x)是P-position(每当你拿走一部分,对手拿走相同的一部分)。

    结论:对于一个Nim游戏的局面(a1,a2,...,an),它是P-position当且仅当a1^a2^...^an=0。

    证明:

    1.无法进行任何移动的局面(terminal position)是P-position。

    显然,因为0^0^...^0=0。

    2.可以移动到P-position的局面是N-position。

    对于局面a1^a2^...^an=k,一定存在某个ai,它的二进制表示在k的最高位上是1,这时ai^k<ai一定成立。则我们可以通过移动将ai改变成ai'=ai^k,此时 a1^a2^...^ai'^...^an=0。

    更广泛的,每个ai--->ai^k(ai^k<ai)都可以实现N--->P。

    3.所有移动都导致N-position的局面是P-position。

    显然,ai--->ai是不合法的移动,所以移动后右项必定非0

    <SG>

    定义DAG游戏,一方每次只能使一颗棋子走一条边,不可走则败。

    定义mex{...}表示最小的不属于这个集合的非负整数。

    对于每个顶点,SG函数:g(x)=mex{ g(y) | y是x的后继 }

    ★SG函数值中,0对应P-position(先手必败),!0对应N-position(先手必胜)

    1.无法进行任何移动的局面(terminal position)是P-position,g(x)=0。

    2.可以移动到P-position的局面是N-position。N-position对应g(x)!=0,其后继必有至少一个0。

    3.所有移动都导致N-position的局面是P-position。P-position对应g(x)=0,其后继必然没有0。

    ★性质:

    1.对于任意的局面,如果它的SG值为0,那么它的任何一个后继局面的SG值不为0。

    2.对于任意的局面,如果它的SG值不为0,那么它一定有一个后继局面的SG值为0。

    结论:当前局面是P-position当且仅当所有棋子所在的位置的SG函数的异或为0。

    进一步地,★总局面的SG值是子局面SG值的异或和

    Nim游戏中,石子数恰好对应g函数。

    考虑游戏的和时,可以将每一个单一游戏视为SG值数目的一堆石子,游戏的和就等价于Nim游戏。

    对于一个可以用SG函数表达的组合游戏,其局面要么先手必胜要么先手必败。

    解法:将复杂的游戏分成若干个子游戏,对于每个子游戏找出它的SG函数,然后全部异或起来就得到了原游戏的SG函数,就可以解决原游戏了。

    前面都是理论,真正实践起来必须熟知SG函数的性质和运用QAQ

    感谢SG函数模板 by jumping_frog

    这篇博客让我恍然大悟……原来SG函数是这个样子。

    计算从1-n范围内的SG值。

    f[]存储可以走的步数,需要从小到大排序

    1.可选步数为1~m的连续整数,直接取模即可,SG(x) = x % (m+1);

    2.可选步数为任意步,SG(x) = x;

    3.可选步数为一系列不连续的数,用GetSG()计算

    SG[a]=mex(SG[b])  a-x=b.

    SG函数套路:分成互不影响的子游戏,考虑子游戏中的转移,得到子游戏的SG值,得到总游戏的SG异或和。

    SG值可以DFS,也可以预处理。

    <阶梯博弈>

    引用自:阶梯博弈(没怎么搞懂) by ~生如夏花

    题意:博弈在一列阶梯上进行,每个阶梯上放着自然数个点,两个人进行阶梯博弈,每一步可以将一个集体上的若干个点( >=1 )移到前面去,最后没有点可以移动的人输。

    转化:从最底开始标号123,将每个奇数台阶的石子视为一堆,则问题可以视为所有奇数阶梯的石子在做Nim博弈。

    说明:如果对手移动偶数堆到奇数堆,我们可以立即从那个奇数堆移动相同数量的石子到偶数堆,反之亦然。

       如果对手移动奇数堆,则我们也移动奇数堆,则转化为奇数堆Nim游戏,反之亦然。

    <二分图博弈>

    引用自:二分图博弈

    题意:状态图(点)为二分图(X集和Y集),任意合法的决策(边)是状态从一类跳转到另一类,不可重复访问点,有起点S,不可再移动视为终点T,到达后胜利。

    题解:

    不妨设起点在二分图的X集中,那么先手只能从X集移动到Y集,后手只能从Y集移动到X集。若最后停留在X集且无法移动则先手负,停留在Y集则后手负。

    考虑该二分图的某个最大匹配。

    若起点S∈X不属于该最大匹配,则先手所转移到的点y∈Y一定属于最大匹配(否则s-y是一个匹配,与最大匹配矛盾),后手沿着最大匹配的边走即可。终点T一定不可能在Y集中(否则,若t在Y集中,s-...-t为一增广路,与最大匹配矛盾)。因此起点S不属于某个最大匹配时,T在同侧,先手必败,后手必胜。

    若起点s∈X属于该最大匹配。则将s从图中删除,再求图的最大匹配。若最大匹配数不变,则s还是不属于某最大匹配,先手必败。否则该图的任意最大匹配都包含s,则先手沿着最大匹配的边走即可,根据上面的分析,起点S属于所有最大匹配时,T在异侧,先手必胜。

    坑:极大极小搜索-博弈

    【01分数规划】

    引用自:[Algorithm]01分数规划——Update:2012年7月27日 by PerSeAwe

    有n个元素可被选择,ai表示选择的收益,bi表示选择的代价,ans=Σ((ai*xi)/(bi*xi))。

    令f(ans)=Σ(a[i]*x[i])-ans*Σ(b[i]*x[i])(特别注意是减去代价),简单变型后得f(ans)=Σ(ai-ans*bi)*xi。

    令di=ai-ans*bi,则f(ans)=Σdi*xi。

    二分ans,当存在方案使f(ans)>=0时,变换回去得到ans<=Σ((ai*xi)/(bi*xi)),也就是可以得到更大的ans。

    所有方案都使f(ans)<0时,变换回去得到ans>Σ((ai*xi)/(bi*xi)),也就是不存在方案满足当前ans,ans应该更小。

    随着ans的增长,d数组单调递减,也就是必然存在一个最大的ans使得存在方案f(ans)>0。

    ★<最优比率环>【BZOJ】1690: [Usaco2007 Dec]奶牛的旅行

    【置换】

    置换就是把n个元素做一个全排列,例如(a1,a2,a3)->(b1,b2,b3)的一一映射就是置换,这n个元素的一个全排列成为一种方案。

    置换之间可以定义乘法,置换A*B就是先做A再做B后的结果,满足结合律,不满足交换律。

    置换可以分解成循环的乘积,并且每个循环节内部依次做len-1次对换就完成了置换。

    (分解的正确性:每个元素有要去的位置,即后继,每个元素原位置有要来的元素,即前驱,于是形成若干个环,每个环都是循环)

    定义循环节为该置换循环分解中循环的个数。

    等价类计数问题:题目中会定义等价关系,目标是统计等价类的个数(本质不同的元素个数)。

    首先用一个置换群来描述等价关系,如果群中的置换可以将一个方案映射到另一个方案,就说二者等价。

    根据群的封闭性定义,F中任意两个置换的乘积也应当在F中

    对于置换f,若一个方案s经过置换后不变,称s为f的不动点,将f的不动点数目记为C(f)

    根据Burnside引理,等价类数目为所有C(f)的平均值。(f∈F)

    考虑经典的方格黑白染色问题,统计C(f)的方式:每个循环内部必须同色,那么C(f)=2^num(num为置换f的循环节)

    假设有k种颜色,则C(f)=k^num,从而得到Polya定理。

    扩展:组合数学——polya

    polya——张弛

    【其它】

    1.错排公式:设D(n)表示n个数错排的方案数(不在原位置)。

    D(n)=(n-1)*(D(n-1)+D(n-2))——第一个数有n-1个放置位置,对于位置k如果放在第1位则D(n-2),否则D(n-1)。

    特别地,D(1)=0,D(2)=1。(计数问题——考虑状态减少的转移,最后一个数字的安排)

    通项求解:

    (1)令D(n)=n!*N(n),容易推到N(n)-N(n-1)=-1/n(N(n-1)-N(n-2),特别地,N(2)-N(1)=1/2。

    将右边不断带入,可以得到N(n)-N(n-1)=(-1)^n/n!,再运用累加法可得D(n)=n!*(1/2!-1/3!+1/4!-...+(-1)^n/n!)

    (2)运用容斥原理,已知集合并的补集(至少i个数不错排),求解集合交(n个数错排)

    +至少0个n!,-至少1个n*(n-1)!,+至少2个C(n,2)*(n-2)!……得到:D(n)=n!-n!/1!-n!/2!...即D(n)=n!*(1/2!-1/3!+1/4!-...+(-1)^n/n!)。

    (3)

    例题:求正确位置数字>=n/2的排列数,转化为<n/2的错排数,组合数枚举错排数字然后运用错排公式。

    2.平方和公式:∑k^2=n(n+1)(2n+1)/6

    3.快速排序:利用分治法,每次找基准数,从右找大,从左找小,找到后同时交换,哨兵相撞后完成,递归。最优O(n log n),最坏O(n^2),平均O(n log n)。

    4.后缀表达式:设置数字栈+符号栈,加入符号时弹出优先度高的符号,弹出符号栈时数字栈栈顶与次顶结合后栈顶-1。

    5.均值不等式:2/(1/a+1/b)<=√ab<=(a+b)/2<=√[(a^2+b^2)/2]

    大步小步法

    原根和指标

    N=8时非递归FFT的演示

    算组合数用公式+乘法逆元更快

    积性函数前缀和(杜教筛)

    生成函数

    多项式开平方 多项式快速幂

    矩阵】【置换】

    【快速傅里叶变换FFT】【NTT】【快速沃尔什变换】【莫比乌斯反演】【构造函数/生成函数】【分数规划】【线性规划】【单纯形】

     

  • 相关阅读:
    javascript中实现类似php 的var_dump
    WKWebView与js交互中产生的内存泄漏
    图片按照指定比例裁剪
    php解析json字符串变量总是空白null
    CocoaPods | iOS详细使用说明
    腾讯IM的那些坑
    JS---案例:协议按钮禁用(倒计时)
    JS---另一个定时器:一次性的
    JS---part5 课程介绍 & part4 复习
    JS---案例:美女时钟
  • 原文地址:https://www.cnblogs.com/onioncyc/p/6146143.html
Copyright © 2020-2023  润新知