[矩阵加速]TR的数列

题目描述

TR非常喜欢数学,经常一个人拿出草稿纸研究奇奇怪怪的数学问题,最近,他突然对数列产生了兴趣,他找到一个数列,类似于斐波拉契,即:Tn=1*f1+2*f2+3*f3+……+n*fn    (fn为斐波拉契的第n项值)

现在TR想请你帮忙求Tn%m的值

输入

两个用空格隔开的整数n和m

1≤n,m≤2^31-1

输出

Tn mod m的值

样例输入

5 5

样例输出

1

解题思路

首先先明白什么是矩阵的乘法

两个矩阵的乘法需满足一个条件就是矩阵A的列数要等于矩阵B的行数才能相乘。

它们构造了一个C矩阵。

如:A(n行,m列),B(m行,p列),则C(n行,p列).

C(i,j) = A(i,1) * B(1,j) + A(i,2) * B(2,j) ...... +A(i,m) * B(m,j)

于是就有矩阵乘法的模板。

要做这道题是需要会做求斐波那契的第n项的矩阵加速

我们定义A:[f1,f2].

B\begin{bmatrix} 0&1 \\ 1&1 \end{bmatrix}

则 A * (B)^n-2即可得到fn。

这里我们还要用矩阵快速幂。

这就是矩阵加速的基本定义。

然而这一道题显然是进阶的。

在这里给出两种方法。

1.

T_{i} = T_{i-1} + i*f_{i}

那么我们就需要将后面那一块用递推表示出来,我们姑且用P定义

则很显然可以推出来这一个东西。

P_{i - 1} + P_{i - 2} = (i - 2) * f_{i - 2} + f_{i - 1}

P_{i} = P_{i - 1} + P_{i - 2} + f_{i - 2} + f_{n}

既然都可这样进行递推了,那么我们将它放到矩阵当中就可以进行运算

我们定义

A\begin{bmatrix} T_i &P_{i} &P_{i+1} &f_{i} &f_{i+1} \end{bmatrix}

B\begin{bmatrix} 1 & 0 & 0 & 0 &0 \\ 0& 0 &1 &0 &0 \\ 1 & 1 & 1 &0 &1 \\ 0& 0 & 2 & 0 &1 \\ 0 & 0 & 1 & 1 &1 \end{bmatrix}

那么仅仅需要A * B^(n - 1)即可

 scanf ("%d%d",&n,&mod);
    A.n = 1;
    A.m = 5;
    B.n = B.m = 5;
    A.c[1][1] = 1;
    A.c[1][2] = 1;
    A.c[1][3] = 2;
    A.c[1][4] = 1;
    A.c[1][5] = 1;
    B.c[1][1] = B.c[2][3] = B.c[3][1] = B.c[3][2] = B.c[3][3] = 1;
    B.c[4][5] = B.c[5][3] = B.c[5][4] = B.c[5][5] = 1;
    B.c[4][3] = 2;
    C = A * qkpow(B,n - 1);
    printf("%lld",C.c[1][1]);

2.

换一种构造方式

我们如果用斐波那契前i项和来推的话其实也可推出来。

至于怎么做,给一个基情链接,只不过有一个地方好像是错了。代码实现也跟我不怎么一样,希望了解思想而自己做出来结果,不然的话。真的会被弄晕的。

不得不说矩阵乘法的代码都很奇葩。

scanf ("%d%d",&n,&mod);
    A.n = 1;
    A.m = 4;
    B.n = B.m = 4;
    A.c[1][1] = 0;
    A.c[1][2] = 1;
    A.c[1][3] = 1;
    A.c[1][4] = 1;
    B.c[1][1] = B.c[2][1] = B.c[2][2] = B.c[3][4] = B.c[4][2] = B.c[4][3] = B.c[4][4] = 1;
    C = A * qkpow(B,n - 1);
    printf("%lld",(C.c[1][2] * n - C.c[1][1] + mod) % mod);

有些东西我直接进行处理的,可能没这么好懂。

猜你喜欢

转载自blog.csdn.net/weixin_43904950/article/details/89045971