首页 > 代码库 > 一道简单的递推题(快速幂+矩阵乘法优化+滚动数组)

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

问题 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\n",ans);
    return 0;
}

 

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