zoukankan      html  css  js  c++  java
  • 矩阵快速幂

    不到四个小时A5道题还是很开心的虽然题都很简单

    今天做题时做到一道名为P哥破解密码的题。

    猜想如果数据小的话可不可以用数位DP做

    设f[i][j]表示到第i个字母,在末尾有j个A的方案数

    推出以下式子:

    f[i+1][0]=f[i][0]+f[i][1]+f[i][2]
    f[i+1][1]=f[i][0]
    f[i+1][2]=f[i][1]

    因为(要求没有连续的三个A)不外乎三种情况:

    1.当前末尾没有A(即这一位填的是B),那么前面的可能是1个A,2个A,或者也是B。

    2.当前末尾一个A(即这一位填的是A且前一位是B),那么只能由前一位是B的转移过来。

    3.当前末尾两个A(即这一位填的是A且前一位是A),那么只能由前一位是A的转移过来。

    因为不出现连续的三个A,所以就没有其他的情况了。

    推出式子后发现n是1e9的,线性推导会超时,然后就使用了矩阵快速幂来优化。

    我突然发现我不会矩阵快速幂。。于是决定去打矩阵快速幂的板子。

    搜到了矩阵快速幂的板子题,我突然发现我还没有打过矩阵乘法。。(弱的真实)

    顺带提一嘴矩阵乘法,就是这个

    ju mul(ju x,ju y)
    {
        for(int i=1;i<=n;++i)
          for(int j=1;j<=n;++j)
            c.m[i][j]=0;
        for(int i=1;i<=n;++i)
          for(int j=1;j<=n;++j)
            for(int p=1;p<=n;++p)
              c.m[i][j]=(c.m[i][j]+x.m[i][p]*y.m[p][j]%mod)%mod;
        return c;
    }
    矩阵乘法

    要求A矩阵的行数与B矩阵的列数相等,方便记忆的话C[i][j]=A的第i行乘B的第j列(但似乎有大佬说这种记忆方法极度肤浅)然后我就看到了这样的一段话

     

    于是

    矩阵快速幂

    #include<bits/stdc++.h>
    #define mod 1000000007
    #define LL long long  
    using namespace std;
    struct ju{
        LL m[101][101];
    }a,e,c;
    LL n;
    LL read()
    {
        LL f=1,x=0;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    ju mul(ju x,ju y)
    {
        for(int i=1;i<=n;++i)
          for(int j=1;j<=n;++j)
            c.m[i][j]=0;
        for(int i=1;i<=n;++i)
          for(int j=1;j<=n;++j)
            for(int p=1;p<=n;++p)
              c.m[i][j]=(c.m[i][j]+x.m[i][p]*y.m[p][j]%mod)%mod;
        return c;
    }
    ju quick_pow(ju a,LL x)
    {
        ju ans=e;
        while(x)
        {
            if(x&1)ans=mul(ans,a);
            a=mul(a,a);
            x>>=1;
        }
        return ans;
    }
    int main()
    {
        n=read();LL k=read();
        for(int i=1;i<=n;++i)
          for(int j=1;j<=n;++j)
            a.m[i][j]=read();
        for(int i=1;i<=n;++i)
            e.m[i][i]=1;//单位矩阵 
        ju ans=quick_pow(a,k);
        for(int i=1;i<=n;++i)
        {
            for(int j=1;j<=n;++j)
              printf("%lld ",ans.m[i][j]%mod);
            printf("
    ");
        }
    } 
    矩阵快速幂

    矩阵加速

    #include<bits/stdc++.h>
    #define mod 1000000007
    #define LL long long 
    using namespace std;
    struct ju{
        LL m[5][5];
    }a,e,c;
    int read()
    {
        int f=1,x=0;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    void init()
    {
        a.m[1][1]=a.m[1][3]=a.m[2][1]=a.m[3][2]=1;//系数矩阵 
        for(int i=1;i<=3;++i)e.m[i][i]=1;//单位矩阵 
    }
    ju mul(ju x,ju y)
    {
        memset(c.m,0,sizeof(c.m));
        for(int i=1;i<=3;++i)
          for(int j=1;j<=3;++j)
            for(int p=1;p<=3;++p)
              c.m[i][j]=(c.m[i][j]+x.m[i][p]*y.m[p][j]%mod)%mod;
        return c;
    }
    ju quick_pow(ju a,LL x)
    {
        ju ans=e;
        while(x)
        {
            if(x&1)ans=mul(ans,a);
            a=mul(a,a);
            x>>=1;
        }
        return ans;
    }
    int main()
    {
        int T=read();
        while(T--)
        {
            int n=read();
            if(n<=3){printf("1
    ");continue;}
            init();
            ju ans=quick_pow(a,n-1);
            printf("%lld
    ",ans.m[1][1]);
        }
    } 
    /*
    f[i-1]       f[i]
    f[i-2] ----> f[i-1]
    f[i-3]       f[i-2]
    f[i] = f[i-1] * 1 + f[i-2] * 0 + f[i-3] * 1
    f[i-1] = f[i-1] * 1 + f[i-2] * 0 + f[i-3] * 0
    f[i-2] = f[i-1] * 0 + f[i-2] * 1 + f[i-3] * 0
    so
    1 0 1
    1 0 0
    0 1 0
    */
    /*
    矩阵(只看第一列)依次是:
    1     1     2     3     4            
    1     1     1     2     3
    0     1     1     1     2(相当于是从f[2],f[1],f[0]这开始的) 
    */ 
    矩阵加速

    斐波那契数列

    #include<bits/stdc++.h>
    #define mod 1000000007 
    #define LL long long 
    using namespace std;
    LL read()
    {
        LL f=1,x=0;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    struct ju{
        LL m[3][3];
    }a,c,e;
    void init()
    {
        for(int i=1;i<=2;++i)e.m[i][i]=1;
        a.m[1][1]=a.m[1][2]=a.m[2][1]=1;
    }
    ju mul(ju x,ju y)
    {
        memset(c.m,0,sizeof(c.m));
        for(int i=1;i<=2;++i)
          for(int j=1;j<=2;++j)
            for(int p=1;p<=2;++p)
              c.m[i][j]=(c.m[i][j]+x.m[i][p]*y.m[p][j]%mod)%mod;
        return c;
    }
    ju quick_pow(ju a,LL x)
    {
        ju ans=e;
        while(x)
        {
            if(x&1)ans=mul(ans,a);
            a=mul(a,a);
            x>>=1;
        }
        return ans;
    }
    int main()
    {
        LL n=read();
        init(); 
        ju ans=quick_pow(a,n);
        printf("%lld
    ",ans.m[2][1]);
    } 
    斐波那契数列

    斐波那契公约数

    有一个很厉害的公式

    gcd(f[a],f[b])=f[gcd(a,b)](证明摘自洛谷题解)

    //gcd(f[a],f[b])=f[gcd(a,b)]
    #include<bits/stdc++.h>
    #define mod 100000000
    #define LL long long
    using namespace std;
    struct ju{
        LL m[3][3];
    }a,c,e;
    int read()
    {
        int f=1,x=0;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    int gcd(int a,int b)
    {
        if(b==0)return a;
        return gcd(b,a%b);
    }
    void init()
    {
        a.m[1][1]=a.m[1][2]=a.m[2][1]=1;
        for(int i=1;i<=2;++i)e.m[i][i]=1;
    }
    ju mul(ju x,ju y)
    {
        memset(c.m,0,sizeof(c.m));
        for(int i=1;i<=2;++i)
          for(int j=1;j<=2;++j)
            for(int p=1;p<=2;++p)
              c.m[i][j]=(c.m[i][j]+x.m[i][p]*y.m[p][j]%mod)%mod;
        return c;
    }
    ju quick_pow(ju a,LL x)
    {
        ju ans=e;
        while(x)
        {
            if(x&1)ans=mul(ans,a);
            a=mul(a,a);
            x>>=1;
        }
        return ans;
    }
    int main()
    {
        int n=read(),m=read();
        int k=gcd(n,m);
        init();
        ju ans=quick_pow(a,k);
        printf("%lld
    ",ans.m[2][1]);
    } 
    斐波那契公约数

    P哥破解密码

    #include<bits/stdc++.h>
    #define mod 19260817
    #define LL long long 
    using namespace std;
    struct ju{
        LL m[5][5];
    }a,c,e;
    int read()
    {
        int f=1,x=0;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    void init()
    {
        for(int i=1;i<=3;++i)e.m[i][i]=1;
        a.m[1][1]=a.m[1][2]=a.m[1][3]=a.m[2][1]=a.m[3][2]=1;
    }
    ju mul(ju x,ju y)
    {
        memset(c.m,0,sizeof(c.m));
        for(int i=1;i<=3;++i)
          for(int j=1;j<=3;++j)
            for(int p=1;p<=3;++p)
              c.m[i][j]=(c.m[i][j]+x.m[i][p]*y.m[p][j]%mod)%mod;
        return c;
    }
    ju quick_pow(ju a,LL x)
    {
        ju ans=e;
        while(x)
        {
            if(x&1)ans=mul(ans,a);
            a=mul(a,a);
            x>>=1;
        }
        return ans;
    }
    int main()
    {
        int T=read();
        init();
        while(T--)
        {
            int n=read();
            ju ans=quick_pow(a,n);
            printf("%lld
    ",((ans.m[1][1]+ans.m[2][1])%mod+ans.m[3][1])%mod);
        }
    } 
    /*
    f[i+1][0]=f[i][0]+f[i][1]+f[i][2]
    f[i+1][1]=f[i][0]
    f[i+1][2]=f[i][1]
    */
    P哥破解密码

    嗦不出话

  • 相关阅读:
    [NOIP2010]引水入城
    [NOIP2009]靶形数独
    设计模式学习笔记——桥接模式(Bridge)
    BootStrap3.0学习--JavaScript 插件
    BootStrap3.0学习--组件
    BootStrap3.0学习--全局 CSS 样式
    BootStrap3.0学习--起步
    设计模式之第11章-建造者模式(Java实现)
    设计模式之第10章-桥接模式(Java实现)
    设计模式之第9章-原型模式(Java实现)
  • 原文地址:https://www.cnblogs.com/yyys-/p/11390988.html
Copyright © 2011-2022 走看看