• 一道简单的递推题(快速幂+矩阵乘法优化+滚动数组)


    问题 F: 一道简单的递推题

    时间限制: 1 Sec  内存限制: 128 MB
    提交: 546  解决: 48
    [提交][状态][讨论版]

    题目描述

    存在如下递推式:
    F(n+1)=A1*F(n)+A2*F(n-1)+...+An*F(1)
    求第K项的值对1000000007取模的结果

    输入

    单组测试数据

    第一行输入两个整数 n , k (1<=n<=100,n<k<=10000000000)

    第二行输入 n 个整数 F(1)   F(2)   ...   F(n)

    第三行输入 n 个整数A1   A2   ...   An 

    输出

    输出一个整数

    样例输入

    2   3
    1   2
    3   4

    样例输出

    10


    今天做这个题,发现这个题真乃卡时间的神题...让我学到了很多..
    - 第一个是我像平时一样上快速幂的模板,返回一个矩阵结构体,但是我发现连跑都跑不了 = =,后面发现是由于矩阵结构体内开了一个 200*200 的二维数组,二函数返回不了这么大空间的结构体,
    我开始一直以为玄学,一直改一直改,改了1个多小时,后来把常量改成 100,没想到就可以跑了,竟然是这个原因,又学习到一个!

    - 第二个是我改了之后AC不了,一直提醒时间超限,然后群里dalao教我新姿势:优化的矩阵乘法和滚动数组.
    Matrix mult(Matrix a,Matrix b,int n)
    {
        Matrix temp;
        for(int i=0; i<n; i++)
        {
            for(int k=0; k<n; k++)
            {
                if(a.v[i][k] == 0 ) continue;
                for(int j=0; j<n; j++)
                {
                    temp.v[i][j] = (temp.v[i][j]+(a.v[i][k]*b.v[k][j])%mod)%mod;
                }
            }
        }
        return temp;
    }

    以前的:

    Matrix mult(Matrix a,Matrix b,int n){
        Matrix temp;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                for(int k=0;k<n;k++){
                    temp.v[i][j] = (temp.v[i][j]+(a.v[i][k]*b.v[k][j])%mod)%mod;
                }
            }
        }
        return temp;
    }

    这个技巧十分有用!特别是当矩阵高阶并且稀疏的时候~

    滚动数组的优化就真的玄学了...我也不知道为什么快..

    这个题的系数矩阵是:

    A1 A2 ... AN
    1   0    ... 0
    0   1   ...  0
             ....
    0 0     ... 1 0

    AC代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <map>
    #include <vector>
    using namespace std;
    typedef long long LL;
    const LL mod = 1000000007;
    const int N = 102;
    LL f[N];
    struct Matrix
    {
        LL v[N][N];
        Matrix()
        {
            memset(v,0,sizeof(v));
        }
    } M[2];
    Matrix mult(Matrix a,Matrix b,int n)
    {
        Matrix temp;
        for(int i=0; i<n; i++)
        {
            for(int k=0; k<n; k++)
            {
                if(a.v[i][k] == 0 ) continue;
                for(int j=0; j<n; j++)
                {
                    temp.v[i][j] = (temp.v[i][j]+(a.v[i][k]*b.v[k][j])%mod)%mod;
                }
            }
        }
        return temp;
    }
    void pow_mod(LL t,LL n)
    {
        for(int i=0; i<n; i++)
        {
            M[0].v[i][i] = 1;
        }
        while(t)
        {
            if(t&1) M[0] = mult(M[0],M[1],n);
            M[1] = mult(M[1],M[1],n);
            t>>=1;
        }
    }
    int main()
    {
        int n;
        LL k;
        scanf("%d%lld",&n,&k);
        for(int i=0; i<n; i++)
        {
            scanf("%lld",&f[n-1-i]);
        }
        for(int i=0; i<n; i++)
        {
            scanf("%lld",&M[1].v[0][i]);
        }
        for(int i=1; i<n; i++)
        {
            M[1].v[i][i-1] = 1;
        }
        k = k-n;
        pow_mod(k,n);
        LL ans = 0;
        for(int i=0; i<n; i++)
        {
            ans=(ans+M[0].v[0][i]*f[i]%mod)%mod;
        }
        printf("%lld
    ",ans);
        return 0;
    }

     弄了一个矩阵快速幂新板子:

    typedef struct Matrix {
        LL m[maxn][maxn];
        LL r;
        LL c;
        Matrix(){
            r = c = 0;
            memset(m, 0, sizeof(m));
        } 
    } Matrix;
     
    Matrix mul(Matrix m1, Matrix m2, LL mod) {
        Matrix ans = Matrix();
        ans.r = m1.r; ans.c = m2.c;
        for(LL i = 1; i <= m1.r; i++) {
            for(LL j = 1; j <= m2.r; j++) {
                for(LL k = 1; k <= m2.c; k++) {
                    if(m2.m[j][k] == 0) continue;
                    ans.m[i][k] = ((ans.m[i][k] + m1.m[i][j] * m2.m[j][k] % mod) % mod) % mod;
                }
            }
        }
        return ans;
    }
    Matrix quickmul(Matrix m, LL n, LL mod) {
        Matrix ans = Matrix();
        for(LL i = 1; i <= m.r; i++) {
            ans.m[i][i]  = 1;
        }
        ans.r = m.r;
        ans.c = m.c;
        while(n) {
            if(n & 1) ans = mul(m, ans, mod);
            m = mul(m, m, mod);
            n >>= 1;
        }
        return ans;
    }

     滚动数组版:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <map>
    #include <vector>
    using namespace std;
    typedef long long LL;
     
    const LL mod = 1E9+7;
    const LL maxn = 110;
    LL n, k;
    LL f[maxn], a[maxn];
     
    struct Matrix {
        LL m[maxn][maxn];
        LL r;
        LL c;
        Matrix(){
            r = c = 0;
            memset(m, 0, sizeof(m));
        }
    } M[2];
     
    Matrix mul(Matrix m1, Matrix m2, LL mod) {
        Matrix ans = Matrix();
        ans.r = m1.r; ans.c = m2.c;
        for(LL i = 1; i <= m1.r; i++) {
            for(LL j = 1; j <= m2.r; j++) {
                for(LL k = 1; k <= m2.c; k++) {
                    if(m2.m[j][k] == 0) continue;
                    ans.m[i][k] = ((ans.m[i][k] + m1.m[i][j] * m2.m[j][k] % mod) % mod) % mod;
                }
            }
        }
        return ans;
    }
    void quickmul(LL n, LL mod) {
        for(LL i = 1; i <= M[1].r; i++) {
            M[0].m[i][i]  = 1;
        }
        M[0].r = M[1].r;
        M[0].c = M[1].c;
        while(n) {
            if(n & 1) M[0] = mul(M[1], M[0], mod);
            M[1] = mul(M[1], M[1], mod);
            n >>= 1;
        }
    }
     
    int main()
    {
        int n;
        LL k;
        scanf("%d%lld",&n,&k);
        for(int i=1; i<=n; i++)
        {
            scanf("%lld",&f[n-i+1]);
        }
        M[1].c = M[1].r = n;
        for(int i=1; i<=n; i++)
        {
            scanf("%lld",&M[1].m[1][i]);
        }
        for(int i=2; i<=n; i++)
        {
            M[1].m[i][i-1] = 1;
        }
        k = k-n;
        quickmul(k,mod);
        LL ans = 0;
        for(int i=1; i<=n; i++)
        {
            ans=(ans+M[0].m[1][i]*f[i]%mod)%mod;
        }
        printf("%lld
    ",ans);
        return 0;
    }

     终极指针版(目前最快的):

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <map>
    #include <vector>
    using namespace std;
    typedef long long LL;
    const LL mod = 1000000007;
    const int N = 102;
    LL f[N];
    struct Matrix
    {
        LL v[N][N];
        Matrix(){memset(v,0,sizeof(v));}
    } M;
    Matrix* mult(Matrix *a,Matrix *b,int n)
    {
        Matrix * temp=(Matrix *)malloc(sizeof(M));
        temp->v[0][0] = 0;
        // memset(temp->v,0,sizeof(temp->v));
        for(int i=0; i<n; i++)
        {
    
            for(int k=0; k<n; k++)
            {
                if(a->v[i][k] == 0 ) continue;
                for(int j=0; j<n; j++)
                {
                    temp->v[i][j] = (temp->v[i][j]+(a->v[i][k]*b->v[k][j])%mod)%mod;
                }
            }
        }
        return temp;
    }
    void pow_mod(Matrix *a,LL t,LL n)
    {
    
        Matrix * ans=(Matrix *)malloc(sizeof(M));
        for(int i=0; i<n; i++)
        {
            ans->v[i][i] = 1;
        }
        while(t)
        {
            if(t&1) ans = mult(a,ans,n);
            a = mult(a,a,n);
            t>>=1;
        }
        LL res = 0;
        for(int i=0; i<n; i++)
        {
            res=(res+ans->v[0][i]*f[i]%mod)%mod;
        }
        printf("%lld
    ",res);
    }
    int main()
    {
        int n;
        LL k;
        scanf("%d%lld",&n,&k);
        for(int i=0; i<n; i++)
        {
            scanf("%lld",&f[n-1-i]);
        }
        for(int i=0; i<n; i++)
        {
            scanf("%lld",&M.v[0][i]);
        }
        for(int i=1; i<n; i++)
        {
            M.v[i][i-1] = 1;
        }
        k = k-n;
        pow_mod(&M,k,n);
        return 0;
    }
  • 相关阅读:
    centos7查看系统版本,查看机器位数x86-64
    CentOS7下安装mysql5.6修改字符集为utf8并开放端口允许远程访问
    CentOS7下mysql5.6修改默认编码
    使用swagger作为restful api的doc文档生成
    在idea中maven项目jdk编译version总是跳到1.5
    国内maven镜像,快的飞起
    醒悟,珍惜时间,学会利用资源
    重定向Http status code 303 和 302
    jackson简单使用,对象转json,json转对象,json转list
    2017 年度码云新增项目排行榜 TOP 50,为它们打“call”
  • 原文地址:https://www.cnblogs.com/liyinggang/p/6985728.html
Copyright © 2020-2023  润新知