• 高手训练矩乘T3


    题目地址

    <前言>

    高手训练矩乘第三题。

    有幸分锅,无能无力。

    望谅解。

    <正文>

    题目大意

    给你一个k维每维长n的斐波那契数维体。

    求值的和。

    eg:以下为2维长4的表。

    (1) (2) (3) (4)
    1 1 2 3
    1 2 3 5
    2 3 5 8
    3 5 8 13

    求和即可,题意简单易懂。

    (n,kleq5)

    直接列出n维表,暴力统计。

    预计得分20

    (无脑向)

    (k=1)

    一维数表?好办。

    斐波那契前缀和公式:

    [f_1+f_2+……+f_i=f_{i+2}-1 ]

    暴力矩乘n+2项,再减一。

    基本的斐波那契转移大概可以直接套模板。

    预计得分20.

    部分分向。

    (kleq100)

    可能就是不用矩阵快速幂的得分吧,不懂就瞎猜的zqy。

    总之我也没写,有兴趣自己写吧。

    直接递推的话大概可能似乎就是这个分,我已经懒得思考了。

    讲一下递推的思路:

    • (S(k,i))为第i层k-1维超立方体的总和。这么说十分抽象,关键是高手训练的题解上写的东西不是人能看的,花了我好久时间理解。

    举个栗子:

    高维的以此类推,相当于将k-1维超立方体看成一大块,k维超立方体中总共有n大块,S就是其中第i大块的价值和。

    • 理解这个后。我们发现答案为(S(k+1,1)),k-1与k之间的转移:

    [egin{aligned}&S(k,0)=sum _{i=0}^{i<n} S(k-1,i)\& S(k,1)=sum_{i=1}^{ileq n}S(k-1,i)\&S(k,i)=S(k,i-1)+S(k,i-2)[i>=2]end{aligned} ]

    初值:这个。。。显然啊,等价形式的两种表达而已。

    递推:找规律易得cy,别管怎么来的,反正它就是个类斐波那契数列。

    然后答案你就可以暴力计算了。预计得分就是这个部分分吧。(瞎猜无证)

    (T leq 100,n,k leq 10^9)

    看到这个数据范围,少年你们还在等什么,log级算法没跑了啊,矩乘走起。

    然后你发现事情十分棘手,对于给定的k,怎么快速计算(sum _{i=1}^{i leq n}S(k,i))呢?

    因为每个k的数列都是类f数列,(S(k,i))可以用(aS(k,0)+bS(k,1))表示,a,b为斐波那契数列相邻两项,后边的事大概就是求一个ab的前缀和,瞎搞就成。

    矩乘的具体步骤,可以参考

    [egin{bmatrix}F_{i-1}&F_iend{bmatrix}=egin{bmatrix}F_{i-2}&F_{i-1}end{bmatrix} egin{bmatrix} 0 &1\1&1end{bmatrix}\ egin{bmatrix}S(k,0)&S(k,1)end{bmatrix}=egin{bmatrix}S(k-1,0)&S(k-1,1)end{bmatrix}egin{bmatrix}F_n&F_{n+1}-1\F_{n+1}-1&F_{n+2}-1end{bmatrix} ]

    至于上面的转移矩阵,其实是可以根据斐波那契前缀和公式推导得到的。

    然后就两个矩乘,完结撒花。

    (mathrm{Code:})

    #include <bits/stdc++.h>
    #define mod 1000000007
    #define int long long
    using namespace std;
    int read() 
    {
        int s = 0, w = 1;
        char c = getchar();
        while ((c < '0' || c > '9') && c != '-') c = getchar();
        if (c == '-')
            w = -1, c = getchar();
        while (c <= '9' && c >= '0') s = (s << 3) + (s << 1) + c - '0', c = getchar();
        return s * w;
    }
    inline int mul(int a, int b) { return 1LL * a * b % mod; }
    inline int add(int a, int b) { return a + b >= mod ? a + b - mod : a + b; }
    struct matrix 
    {
        int a[10][10];
        int n, m;
        inline matrix(int nn,int mm) 
    	{
            n = nn;
            m = mm;
            memset(a, 0, sizeof(a));
        }
        inline matrix operator*(matrix b) 
    	{
            matrix c(n,b.m);
            for (int i = 0; i < c.n; ++i)
                for (int j = 0; j < c.m; ++j)
                    for (int k = 0; k < m; ++k) 
    				    c.a[i][j] = add(c.a[i][j], mul(a[i][k], b.a[k][j]));
            return c;
        }
    };
    int n, T, k;
    matrix mpower(matrix a, int b) 
    {
        matrix s(a.n,a.n);
        for (int i = 0; i < s.n; ++i) s.a[i][i] = 1;
        for (; b; b >>= 1) 
    	{
            if (b & 1)
                s = s * a;
            a = a * a;
        }
        return s;
    }
    signed main() 
    {
        T = read();
        while (T--) 
    	{
        	matrix  a(1,2), d(2,2), dd(2,2), f(1,2);
            a.a[0][1] = 1;
            d.a[0][1] = d.a[1][0] = d.a[1][1] = 1;
            n = read();
            k = read();
            a = a * mpower(d, n );
            int a1 = a.a[0][0], b1 = a.a[0][1], a2 = a.a[0][1], b2 = a.a[0][1]+a.a[0][0];
            dd.a[0][0] = a1;
            dd.a[0][1] = a2 - 1;
            dd.a[1][0] = b1 - 1;
            dd.a[1][1] = b2 - 1;
            f.a[0][1] = 1;
            f = f * mpower(dd, k);
            printf("%lld
    ", f.a[0][1]);
        }
        return 0;
    }
    

    <后记>

    瞎写的程序,不能信。

    ——来自菜鸡zqy的祝福。

    寒假要结束了,容我缓缓。

    这题,说实话,我是30号晚上爆肝搞得。

    在此之前这题没搞过。唉

    原文地址https://www.cnblogs.com/zqytcl/p/12244512.html,发布于博客园,转载请注明出处。

  • 相关阅读:
    HTML5 跨文档消息传输
    Cordova 本地项目创建方法
    远程登录协议
    Linux mii-tool命令
    Linux ethtool命令
    Linux内核阅读相关
    C语言介绍
    Proc-fs 编程
    Linux syslog介绍
    Mpich编程
  • 原文地址:https://www.cnblogs.com/yywxdgy/p/12244512.html
Copyright © 2020-2023  润新知