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

问题 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;
}
时间: 2024-07-30 10:05:11

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

[POJ 3150] Cellular Automaton (矩阵快速幂 + 矩阵乘法优化)

Cellular Automaton Time Limit: 12000MS   Memory Limit: 65536K Total Submissions: 3048   Accepted: 1227 Case Time Limit: 2000MS Description A cellular automaton is a collection of cells on a grid of specified shape that evolves through a number of dis

斐波那契优化 快速幂+矩阵乘法

题目:你能求得第n个斐波那契数吗?0<n<maxlongint 由于结果太大,输出的结果mod32768 思路:一般的求斐波那契数列的方法有递归,动归,或者用滚动优化,但是空间复杂或者时间复杂度都太高了,现在有一种用矩阵加快速幂的优化算法,可以让时间复杂度维持在logn. 具体的 初始化一个2×2的矩阵,初始值为{1,0,0,1} 则分别代表{a2,a1,a1,a0},把此矩阵平方后得到{2,1,1,0}分别代表{a3,a2,a2,a1}如此下去,便可以得到规律,其实这个算法主要就是优化在快速

HDU 4965 Fast Matrix Caculation ( 矩阵乘法 + 矩阵快速幂 + 矩阵乘法的结合律 )

HDU 4965 Fast Matrix Calculation ( 矩阵乘法 + 矩阵快速幂 + 矩阵乘法的结合律 ) #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define MAX_SIZE 1001 #define CLR( a, b ) memset( a, b, sizeof(a) ) #define MOD 6 typedef long lo

BZOJ 1411&amp;&amp;Vijos 1544 : [ZJOI2009]硬币游戏【递推,快速幂】

1411: [ZJOI2009]硬币游戏 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 897  Solved: 394[Submit][Status][Discuss] Description Orez很喜欢玩游戏,他最近发明了一款硬币游戏.他在桌子的边缘上划分出2*n个位置并按顺时针把它们标号为1,2,……,2n,然后把n个硬币放在标号为奇数的位置上.接下来每次按如下操作:在任意两个硬币之间放上一个硬币,然后将原来的硬币拿走:所放硬币的正反面

poj 3735 Training little cats 矩阵快速幂+稀疏矩阵乘法优化

题目链接 题意:有n个猫,开始的时候每个猫都没有坚果,进行k次操作,g x表示给第x个猫一个坚果,e x表示第x个猫吃掉所有坚果,s x y表示第x个猫和第y个猫交换所有坚果,将k次操作重复进行m轮,问最后这n个猫各自有多少坚果. 题解:构造(n+1)*(n+1)的单位矩阵,data[i][j]表示第i个猫与第j个猫进行交换,最后一列的前n项就是每个猫的坚果数目,s操作就交换对应行,矩阵快速幂时间复杂度O(n^3*log2(m))会超时,我们注意到在n*n的范围内每一行只有一个1,利用稀疏矩阵的

模板——矩阵快速幂+矩阵乘法

#include<bits/stdc++.h> using namespace std; const long long P=1e9+7; long long n,m; struct nob{ long long juzhen[105][105]; friend nob operator * (const nob &a,const nob &b){ nob c; for (int i=1; i<=n; i++){ for (int l=1; l<=n; l++){

一堆递推题

目录 一堆递推题 P1367[训练题]爬楼梯[2] 描述 輸入 輸出 輸入範例 1 輸出範例 1 提示 思路 铺瓷砖 描述 輸入 輸出 輸入範例 1 輸出範例 1 思路 城市路径 描述 輸入 輸出 輸入範例 1 輸出範例 1 提示 思路 彩带 描述 輸入 輸出 輸入範例 1 輸出範例 1 提示 思路 斐波那契前N项和 描述 輸入 輸出 輸入範例 1 輸出範例 1 提示 思路 偶数个3 描述 輸入 輸出 輸入範例 1 輸出範例 1 思路 回文拆分 描述 輸入 輸出 輸入範例 1 輸出範例 1 思路

hdu 1267 下沙的沙子有几粒?(二维递推题)

题意:就是给你m个H和n个D,然后从左开始数H的累积个数总是不比D的累计数少的排列有多少种举一个测试案例吧:3个H和1个D总共有3种排列,依次是:H D H H,H H D H,H H  H D三种排列,亲~意思应该懂了吧?!呵呵... 思路:递推公式为:a[m][n]=a[m-1][n]+a[m][n-1];然后当n=0的时候无论m取何值都是1,递推公式怎么推来的呢?我现在说下我的思路吧!假设3个H和2个D是由2个H和2个D还有3个H一个D推来的,2个H和2个D总共有H D H D,H H D

用矩阵乘法优化递推

(有关矩阵乘法的基本规则请自行搜索) 引例:求斐波那契数列的第 n 项 mod 1000000007 的值,n <= 1018. 分析:斐波那契数列的递推式为 f(n) = f(n-1)+f(n-2),直接循环求出 f(n) 的时间复杂度是 O(n),对于题目中的数据范围显然无法承受.很明显我们需要对数级别的算法. 由于 f(n) = 1*f(n-1) + 1*f(n-2) 这样的形式很类似于矩阵的乘法,所以我们可以先把这个问题复杂化一下,将递推求解 f(n) 与 f(n-1) 的过程看作是某两