zoukankan      html  css  js  c++  java
  • 【dp】【矩阵乘法快速幂】

    快速入门视频: av56433157

    1> p1926 斐波那契

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    using namespace std;
    long long n;
    const int mod=1000000007;
    long long nw[2][2],ans[2][2];
    long long t[2][2];
    
    void mul1()
    {
        memset(t,0,sizeof(t));
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
                for(int k=0;k<2;k++)
                    t[i][j]+=(ans[i][k]*nw[j][k])%mod;
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
                ans[i][j]=t[i][j];
    }
    void mul2()
    {
        memset(t,0,sizeof(t));
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
                for(int k=0;k<2;k++)
                    t[i][j]+=(nw[i][k]*nw[j][k])%mod;
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
                nw[i][j]=t[i][j];
    }
    void mul3()
    {
        long long as=0;
        for(int i=0;i<2;i++) as=(as+ans[0][i])%mod;
        printf("%lld
    ",as);
    }
    
    int main()
    {
        scanf("%lld",&n);
        n-=2;
        if(n<=0) 
        {
            printf("1
    ");
            return 0;
        }
        
        nw[0][0]=nw[1][0]=nw[0][1]=1;
        ans[0][0]=ans[1][1]=1;
        while(n)
        {
            if(n&1) mul1();
            n>>=1,mul2();
        }
        mul3();
        
        return 0;
    }

    2>广义斐波那契数列

     这道题中的乘法,会爆ll,

    所以只能用pow_add(),具体见代码

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    using namespace std;
    long long a,c,a0,n,mod,g;
    long long ans[3][3],nw[3][3],t[3][3];
    long long pow_add(long long x,long long y)
    {
        long long ans=0;
        while(y)
        {
            if(y&1) ans=(ans+x)%mod;
            x=(x+x)%mod;
            y>>=1;
        }
        return ans;
    }
    
    void mul1()
    {
        memset(t,0,sizeof(t));
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
                for(int k=0;k<3;k++)
                    t[i][j]=(t[i][j]+pow_add(ans[i][k],nw[k][j]))%mod;
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
                ans[i][j]=t[i][j];
    }
    void mul2()
    {
        memset(t,0,sizeof(t));
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
                for(int k=0;k<3;k++)
                    t[i][j]=(t[i][j]+pow_add(nw[i][k],nw[k][j]))%mod;
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
                nw[i][j]=t[i][j];
    }
    
    int main()
    {
        scanf("%lld%lld%lld%lld%lld%lld",&mod,&a,&c,&a0,&n,&g);
        c%=mod,a%=mod,a0%=mod;
        long long a1=(pow_add(a,a0)+c)%mod;
        if(n==1)
            printf("%d
    ",a1%g);
        if(n<2) return 0;
        n-=2;
        
        ans[0][0]=a,ans[0][2]=ans[1][0]=ans[2][2]=1;
        nw[0][0]=a,nw[0][2]=nw[1][0]=nw[2][2]=1;
        while(n)
        {
            if(n&1) mul1();
            n>>=1,mul2();
        }
        printf("%d
    ",(pow_add(a1,ans[0][0])+pow_add(a0,ans[0][1])+pow_add(c,ans[0][2]))%mod%g);
        return 0;
    }

    3>ch30摆花

    用矩阵快速幂加速dp,优化时间复杂度和空间复杂度

    60->100

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    using namespace std;
    int n,m;
    const int N=103,mod=1e9+7;
    long long nw[N][N],ans[N],t[N][N],tt[N];
    
    void mul1()
    {
        memset(tt,0,sizeof(tt));
        for(int i=0;i<=n;i++)
                for(int k=0;k<=n;k++)
                    tt[i]=(tt[i] +nw[i][k]*ans[k]%mod) %mod;
        for(int i=0;i<=n;i++)
                ans[i]=tt[i];
    }
    void mul2()
    {
        memset(t,0,sizeof(t));
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
                for(int k=0;k<=n;k++)
                    t[i][j]=(t[i][j] +nw[i][k]*nw[k][j]%mod)%mod;
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
                nw[i][j]=t[i][j];
    }
    void mul3()
    {
        long long as=0;
        for(int i=0;i<=n;i++) as=(as+ans[i])%mod;
        printf("%lld
    ",as);
    }
    
    int main()
    {
        scanf("%d%d",&m,&n);
        int x;
        for(int i=0;i<=n;i++) nw[i][0]=nw[0][i]=1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                scanf("%1d",&x);
                nw[i][j]=x^1;
            }
        
        ans[0]=1;
        while(m)
        {
            if(m&1) mul1();
            m>>=1,mul2();
        }
        mul3();
        
        return 0;
    }
  • 相关阅读:
    ES6(二)解构赋值详解
    面试题
    说出x的结果,并解释为什么?
    23种设计模式
    自定义滚动条
    JavaScript之数据类型
    [[转]CSS浮动原理
    正选反选JS
    让2个并列的div根据内容自动保持同等高度js
    jquery鼠标滑过展示图片时显示详情
  • 原文地址:https://www.cnblogs.com/xwww666666/p/11519655.html
Copyright © 2011-2022 走看看