• Codeforces 392C Yet Another Number Sequence (矩阵快速幂+二项式展开)


    题意:已知斐波那契数列fib(i) , 给你n 和 k , 求∑fib(i)*ik (1<=i<=n)

    思路:不得不说,这道题很有意思,首先我们根据以往得出的一个经验,当我们遇到 X^k 的形式,当 X 很大,k很小时,我们可以利用二项式定理进行展开,然后求出递推式在利用矩阵加速

    推导过程:

    已知 fib(1) = 1, fib(2) = 1,fib(i) = fib(i-1) + fib(i-2);

           Ai(k) =fib(i)*i^k;

    根据数学归纳法,我们可知 fib(i+1)*(i+1)^k = ( fib(i) + fib(i-1) ) * (i+1)^k 必然成立

    将上式进行二项式展开 

    上式 = ( fib(i) + fib(i-1) ) * {C[k][0]*i^0 + C[k][1]*i^1 +...+C[k][k]*i^k}; 

           = C[k][0]*(i^0* fib(i) + i^0*fib(i-1) ) + C[k][1]*(i^1* fib(i) + i^1*fib(i-1) )....(乘法结合律

    我们定义 g1[i][a] = fib(i)*i^a , g2[i][a] = fib(i-1)*i^a

    将定义的g1 , g2 带入上式中得到递推公式

    g1[i][k] = C[k][0]*(g1[i-1][0]+g2[i-1][0])+C[k][1]*(g1[i-1][1]+g2[i-1][1])+...+C[k][k](g1[i-1][k]+g2[i-1][k]);

    g2[i][k]= C[k][0]*g1[i-1][0] +C[k][1]*g1[i-1][1]+..+C[k][k]*g1[i-1][k];

    最后再根据递推式写出构造矩阵即可

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #define ll long long
    using namespace std;
    ll N,M,P;
    const ll MOD=1000000007;
    ll C[85][85];
    struct  Matrix
    {
        ll m[85][85];
    };
    
    Matrix  A;
    
    Matrix  I;
    
    void get_C()
    {
        memset(C,0,sizeof(C));
        C[0][0]=1;
        for(int i=1;i<=82;i++)
        {
            C[0][i]=C[i][i]=1;
            for(int j=1;j<=i;j++)
            {
                C[j][i]=(C[j][i-1]+C[j-1][i-1])%MOD;
            }
        }
    }
    
    void make_I(int k)
    {
        memset(I.m,0,sizeof(I.m));
        for(int i=0;i<=2*(k+1);i++)
          for(int j=0;j<=2*(k+1)+1;j++)
           if(i==j)
           I.m[i][j]=1;
    }
    
    void make_A(int k)
    {
        memset(A.m,0,sizeof(A.m));
        for(int i=0;i<=k;i++)
        {
            for(int j=0;j<=i;j++)
            {
                A.m[i][j]=C[j][i];
            }
        }
        for(int i=0;i<=k;i++)
        {
            for(int j=0;j<=i;j++)
            {
                A.m[i+k+1][j]=C[j][i];
            }
        }
        for(int i=0;i<=k;i++)
        {
            for(int j=k+1;j<=2*(k+1)-1;j++)
            {
                A.m[i][j]=C[j-k-1][i];
            }
        }
        A.m[2*(k+1)][k]=1;
        A.m[2*(k+1)][2*(k+1)]=1;
    }
    
    Matrix multi(Matrix a,Matrix b)
    {
        Matrix ans;
        for(int i=0;i<=N;i++)
        {
           for(int j=0;j<=M;j++)
           {
              ans.m[i][j]=0;
              for(int k=0;k<=P;k++)
              {
                 ans.m[i][j]=(ans.m[i][j]+a.m[i][k]*b.m[k][j])%MOD;
              }
              ans.m[i][j]%=MOD;
           }
        }
        return ans;
    }
    
    Matrix power(Matrix a,ll k)
    {
        Matrix ans=I,p=a;
        while(k)
        {
          if(k&1)
          {
            ans=multi(ans,p);
          }
          k>>=1;
          p=multi(p,p);
        }
        return ans;
    }
    
    int main()
    {
        ll n;
        int k;
        get_C();
        while(cin>>n>>k)
        {
            if(n==1)
            {
                cout<<"1"<<endl;
                continue;
            }
            else
            {
                make_A(k);
                make_I(k);
                N=M=P=2*(k+1);
                Matrix ans = power(A,n);
                ll num=0;
                for(int i=0;i<M;i++)
                num=(num+ans.m[2*(k+1)][i])%MOD;
                cout<<num<<endl;
            }
        }
        return 0;
    }
  • 相关阅读:
    微信小程序在扫一扫进入小程序的时候 安卓手机后台继续运行的常规处理
    在微信小程序上,帮助中心界面实现类似手风琴案例
    使用artTemplate的模板引擎,使用简单
    使用原生JavaScript实现图片预加载,方法简单代码少
    在wepy框架中 使用promise对发送网络请求进行封装 包括post跟get请求
    JavaScript实现按字典排序进行md5加密, 以及个人在小程序也可以实现
    当在微信扫一扫进入小程序 并获取到二维码的参数 从而实现扫码进入小程序
    第九章:看看精彩的世界-使用网络技术
    玉渊潭公园
    军事博物馆
  • 原文地址:https://www.cnblogs.com/simplekinght/p/6674256.html
Copyright © 2020-2023  润新知