• 矩阵快速幂好题分享


    poj3420 Quad Tiling
    这些方案数的题,一般是先找到某些递推式,然后,根据递推式做之后的优化工作。
    首先这是个铺地板的经典问题,对于这类方案数的求解有一个比较重要的思想,就是考虑从小往上的最小的可分割矩阵来分开求方案数。我们首先设\(a_i\)表示i4的方格不可分割的最小矩阵的发案数。这个需要自己画图发现,a1=1,a2=4,a3=2,a4=3...之后发现奇数次为2,偶数次为3.之后考虑递推式n,设f表示它所求的值,那么考虑按最小分割的矩阵分类讨论,f[n]=a1f[n-1]+a2f[n-2]+...+an-1f[1]=f[n-1]+4f[n-2]+2(f[n-3]+f[n-5]...)+3(f[n-4]+f[n-6]+...)
    对于这类的递推式子,如果我们要求通项的话,一般的做法就是将f[n-1]写出,然后相加减即可。(有点错位相减的意思。)
    那么f[n-1]=f[n-2]+4
    f[n-3]+2(f[n-4]+f[n-6]+...)+3(f[n-5]+f[n-7]+...)
    两者做和,得出f[n]=5f[n-2]+6f[n-3]+5(f[n-4]+f[n-5]+...)
    则我们继续,f[n-1]=5f[n-3]+6f[n-4]+5(f[n-5]+f[n-6]+...)
    两式相减:f[n]-f[n-1]=5f[n-2]+f[n-3]-f[n-4].则f[n]=f[n-1]+5f[n-2]+f[n-3]-f[n-4].
    之后直接用矩阵快速幂递推即可。

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <stdio.h>
    #include <string.h>
    #define ll long long
    using namespace std;
    const int N=5;
    int n,m;
    struct wy
    {
        ll a[N][N];
        wy() {memset(a,0,sizeof(a));}
        inline void clear() {memset(a,0,sizeof(a));}
        wy friend operator*(wy a,wy b)
        {
            wy c;
            for(int i=1;i<N;++i)
                for(int j=1;j<N;++j)
                    for(int k=1;k<N;++k) c.a[i][j]=((c.a[i][j]+a.a[i][k]*b.a[k][j])%m+m)%m;
            return c;         
        } 
        wy friend operator^(wy a,ll y)
        {
            wy c;
            for(int i=1;i<N;++i) c.a[i][i]=1;
            while(y)
            {
                if(y&1) c=c*a;
                y>>=1;
                a=a*a;
            }
            return c;
        }
    };
    int main()
    {
    //    freopen("1.in","r",stdin);
        while(scanf("%d%d",&n,&m))
        {
            if(n==0&&m==0) break;
            wy A,B,C;
            A.a[1][1]=1;A.a[1][2]=5;
            A.a[1][3]=11;A.a[1][4]=36;
            if(n<=4) printf("%lld\n",A.a[1][n]%m);
            else
            {
                B.a[2][1]=1;B.a[3][2]=1;
                B.a[4][3]=1;B.a[1][4]=-1;
                B.a[2][4]=1;B.a[3][4]=5;
                B.a[4][4]=1;
                B=B^(n-4);
                C=A*B;
                printf("%lld\n",C.a[1][4]%m);
            }
        }
        return 0;
    }
    

    #2476. 战场的数目
    真的是神仙题目...
    首先可以发现战场的周长一定是偶数,这个可以考虑当初没合并之前每个小正方形的周长都是6,合并的时候两个重合的面导致两个面被不计,所以周长一定是偶数。既然如此,我们可以考虑设f[i]表示周长为2i的方案数。接下来的就是讨论方案数中最难的一部分,怎么划分方案,可以用上之前的信息。首先我们可以想到左右两边的1似乎有某些性质,考虑若最左边或最右边有一个1,我们把这个1去掉,减少的周长为2,即f[i-1]。那么这个方案数就是2f[i-1]。但这样会有重复,考虑两边都有1的情况,我们考虑将这两边的1都去掉,即f[i-2]。接下来考虑两边都没1的情况,我们可以将最下面一层去掉。这样仍是我们之前的状态。最后f[i]=3*f[i-1]-f[i-2],最后别忘了减去所有矩阵的方案,即n-1.直接用矩阵加速即可。

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int P=987654321;
    struct wy
    {
        ll a[3][3];
        wy() {memset(a,0,sizeof(a));}
        void clear(){memset(a,0,sizeof(a));}
        wy friend operator*(wy a,wy b)
        {
            wy c;
            for(int i=1;i<=2;++i)
                for(int j=1;j<=2;++j)
                    for(int k=1;k<=2;++k) c.a[i][j]=((c.a[i][j]+a.a[i][k]*b.a[k][j])%P+P)%P;
            return c;
        }
        wy friend operator^(wy x,ll y)
        {
            wy ans;
            for(int i=1;i<=2;++i) ans.a[i][i]=1;
            while(y)
            {
                if(y&1) ans=ans*x;
                y>>=1;
                x=x*x;    
            }    
            return ans;
        } 
    }A,B,C;
    int main()
    {
    //    freopen("1.in","r",stdin);
        int x;
        while(scanf("%d",&x))
        {
            if(!x) break;
            if(x%2==1||x<8) printf("%d\n",0);
            else
            {
                if(x==8) {printf("%d\n",2);continue;}
                else if(x==10) {printf("%d\n",9);continue;}
                int d=x/2;
                A.a[1][1]=5;A.a[1][2]=13;
                B.a[1][1]=0;B.a[1][2]=-1;
                B.a[2][1]=1;B.a[2][2]=3;
                B=B^(d-5);
                C=A*B;
                printf("%lld\n",((C.a[1][2]-(d-1))%P+P)%P);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    如何查找YUM安装的JAVA_HOME环境变量详解
    Linux下设置和查看环境变量
    jar包部署脚本
    CentOS7开启防火墙及特定端口
    nohup 命令(设置后台进程): appending output to ‘nohup.out’ 问题
    重点|183道Java面试题可以说很详细了
    JVM性能调优
    【Notepad++】notepad++主题和字体设置(非常好看舒服的)
    spring-boot-maven-plugin 安装本地jar 包
    UserAgentUtils 获取浏览器信息
  • 原文地址:https://www.cnblogs.com/gcfer/p/15818146.html
Copyright © 2020-2023  润新知