Codeforces Round #230---C:Yet Another Number Sequence(矩阵快速幂)

题目:

戳一戳~~

给定k,n,定义Ai = Fi + i ^ k,其中Fi为斐波拉契数列,求Ai数列的前n项和

分析:

推荐阅读:根据递推公式构造系数矩阵

容易得到递推式:

S_n = S_{n-1} + n^kF_n=S_{n-1} + (F_{n-1}+F_{n-2})n^k

n^k 没有递推式,这样构造的系数矩阵和n有关,就不能矩阵快速幂,考虑二项式定理:

n^k=(n-1+1)^k=C_{k}^{0}(n-1)^k+C_{k}^{1}(n-1)^k-1+...+C_{k}^{k}(n-1)^0

这样n^k也是递推形式的,代入上式构造如下的矩阵:

\begin{pmatrix} C_{k}^0 &C_k^1 &... &C_k^k &C_k^0 &C_k^1&...&C_k^k &0\\ 0&C_{k-1}^0 & ... &C_{k-1}^{k-1} & 0&C_{k-1}^0 & ... &C_{k-1}^{k-1}&0 \\ \vdots & \vdots& \vdots & \vdots& \vdots& \vdots& \vdots& \vdots&\vdots \\ 0&0 &...&1&0 &0&...&1 &0\\ C_{k}^0 &C_k^1 &... &C_k^k &0 &0&...&0 &0\\ 0&C_{k-1}^0 & ... &C_{k-1}^{k-1} & 0&0 & ... &0 &0 \\ \vdots & \vdots& \vdots & \vdots& \vdots& \vdots& \vdots& \vdots &\vdots\\ 0&0 &...&1&0 &0&...&0&0\\ C_{k}^0 &C_k^1 &... &C_k^k &C_k^0 &C_k^1&...&C_k^k &1 \end{pmatrix} *\begin{pmatrix} (n-1)^kF_ {n-1}\\ (n-1)^{k-1}F_ {n-1}& \\ \vdots\\ F_ {n-1}\\ (n-1)^kF_{n-2} \\ (n-1)^{k-1}F_{n-2} \\ \vdots \\ F_{n-2}\\ S_{n-1} \end{pmatrix}

=\begin{pmatrix} n^kF_ n\\ n^{k-1}F_ n& \\ \vdots\\ F_ n\\ n^kF_{n-1} \\ n^{k-1}F_{n-1} \\ \vdots \\ F_{n-1}\\ S_{n} \end{pmatrix}

不难验证系数矩阵的正确性,可以初始化n-1 = 1 ,那么第二个矩阵全为1,矩阵中的组合数通过杨辉三角来预处理,避免溢出,剩下的就是矩阵快速幂了

代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const LL MOD = 1e9+7;
LL n,k,a[100][100],b[100][1],C[50][50];
void cal(){                                 //预处理组合数
    for(int i = 0;i <= k; ++i){
        C[i][0] = 1;
        for(int j = 1;j <= i; ++j)
            C[i][j] = (C[i-1][j-1] + C[i-1][j]) % MOD;
    }
}
void init(){                                 //预处理系数矩阵和答案矩阵
    cal();
    for(int i = 0;i < 2*k+3; ++i) b[i][0] = 1;
    a[2*k+2][2*k+2] = 1;                    
    for(int i = 0;i < k+1; ++i) 
        a[2*k+2][i] = a[2*k+2][i+k+1] = C[k][i];
    for(int i = 0;i < k+1; ++i)
        for(int j = i; j < k+1; ++j)
            a[i][j] = a[i][j+k+1] = a[i+k+1][j] = C[k-i][j-i];
}
void calmatrix1(){
    LL c[100][1] = {0};
    for(int i = 0;i < 2*k+3; ++i)
        for(int j = 0;j < 2*k+3; ++j)
            c[i][0] = (c[i][0] + a[i][j]*b[j][0]) % MOD;
    memcpy(b,c,sizeof(c));
}
void calmatrix2(){
    LL c[100][100] = {0};
    for(int i = 0;i < 2*k+3; ++i)
        for(int j = 0;j < 2*k+3; ++j)
            for(int t = 0;t < 2*k+3; ++t)
                c[i][t] = (c[i][t] + a[i][j]*a[j][t]) % MOD;
    memcpy(a,c,sizeof(c));
}
LL solve(LL x){
    init();
    x -= 1;
    while(x){
        if(x & 1) calmatrix1();
        calmatrix2();
        x >>= 1;
    }
    return b[2*k+2][0];
}
int main()
{
    cin >> n >> k;
    cout << solve(n);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41157137/article/details/89183120