一道简单的递推题(快速幂+矩阵乘法优化+滚动数组)
Posted AC菜鸟机
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一道简单的递推题(快速幂+矩阵乘法优化+滚动数组)相关的知识,希望对你有一定的参考价值。
问题 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; }
以上是关于一道简单的递推题(快速幂+矩阵乘法优化+滚动数组)的主要内容,如果未能解决你的问题,请参考以下文章
[题解][SHOI2013]超级跳马 动态规划/递推式/矩阵快速幂优化