codeforces 392 c Yet Another Number Sequence
2014年2月20日 00:31
题目大意
已知斐波那契数列F1 = 1, F2 = 2, Fi = Fi - 1 + Fi - 2 (i > 2)。定义Ai(k) = Fi × ik (i ≥ 1),求A1(k) + A2(k) + ... + An(k)对1000000007(109+7)取模的结果。(1 ≤ n ≤ 1017; 1 ≤ k ≤ 40)
题目链接: http://codeforces.com/problemset/problem/392/C
解题报告
算法思路
这类题目基本上都是矩阵快速幂。
分析流程
1. 二项式
首先根据二项式定理
可以得到以下等式
2. 简写
为了方便后续公式的书写,我们做如下定义(简写),记
于是上面的公式可以简写为如下形式:
3. 矩阵构造
根据题目意思,令
同时定义一个 k乘1的列向量,该列向量前k-1行均为0,最后一行为1,记为Ik
构造如下矩阵,根据前面简写、定义,可知如下等式成立。
根据上述等式,很容易写出如下的通项公式
4. 初值
根据题目意思,斐波那契数列初值F1 = 1, F2 = 2,可以推断F0 = 1,于是通项公式的初值如下:
5. 求解
部分由矩阵快速幂求解。时间复杂度为O((2k + 3)3 log n)=O(k3 log n)。矩阵快速幂后乘以初值即可得到答案。
代码
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <set> #include <queue> #include <algorithm> using namespace std; typedef long long LL; #define maxn 84 #define MOD 1000000007 LL A[maxn][maxn], C[41][41], ans[maxn][maxn], tp[maxn][maxn]; void gen(int k) { for (int i = 0; i <= k; ++i) { C[i][0] = C[i][i] = 1; } for (int i = 2; i <= k; ++i) { for (int j = 1; j < i; ++j) { C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD; } } for (int i = 0; i <= k; ++i) { for (int j = i; j <= k; ++j) { A[i + k + 1][j] = A[i][j + k + 1] = A[i + k + 1][j + k + 1] = C[j][i]; } } A[2 * k + 1][2 * k + 2] = 1; A[2 * k + 2][2 * k + 2] = 1; for (int i = 0; i < 2 * k + 3; ++i) { ans[i][i] = 1; } } void multi(LL C[][maxn], LL A[][maxn], LL B[][maxn], int n) { memset(tp, 0, sizeof(tp)); for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { for (int k = 0; k < n; ++k) { tp[i][j] = (tp[i][j] + A[i][k] * B[k][j] % MOD) % MOD; } } } memcpy(C, tp, sizeof(tp)); } LL solve(LL n, int k) { gen(k); while (n) { if (n % 2) { multi(ans, A, ans, 2 * k + 3); } multi(A, A, A, 2 * k + 3); n /= 2; } LL res = 0; for (int i = 0; i < 2 * k + 2; ++i) { res = (res + ans[i][2 * k + 2]) % MOD; } return res; } int main() { LL n; int k; cin >> n >> k; cout << solve(n, k) << endl; return 0; }