洛谷 P4451 [国家集训队]整数的lqp拆分
题意简述
设(F_{x})为斐波那契数列第(x)项
将一个数(n)拆分为(a{1}, a{2}, ..., a{m}), 即(a{1} + a{2} +...+ a{m} = n)
求(sumprodlimits_{i =1}^m F_{a_i})
题解思路
递推
设(g(i))为当n = i时的答案
所以
(g(i) = sumlimits_{j = 1} ^ {i - 1} g(j) * F_{i - j} + F_i)
(g(i + 1) = sumlimits_{j = 1} ^ {i} g(j) * F_{i + 1 - j} + F_{i + 1})
(g(i + 1) - g(i))
$ = sumlimits_{j = 1} ^ {i - 1} g(j) * (F_{i + 1 - j} - F_{i - j}) + g(i) * F_1 + F_{i + 1} - F_i(
) = sumlimits_{j = 1} ^ {i - 1} g(j) * F_{i - j - 1} + g(i) + F_{i - 1}(
) = sumlimits_{j = 1} ^ {i - 2} g(j) * F_{i - j - 1} + F_{i - 1} + g(i)(
) = g(i - 1) + g(i)$
所以 (g(i + 1) = 2 * g(i) + g(i - 1)) 且 (g(0) = 0, g(1) = 1)
再直接递推或矩阵快速幂求第(n)项即可
代码
#include <cstdio>
typedef long long ll;
const int mod = 1000000007;
int T, N;
int n;
struct Matrix
{
int a[4][4];
Matrix& operator =(const Matrix& x)
{
for (register int i = 1; i <= N; ++i)
for (register int j = 1; j <= N; ++j)
a[i][j] = x.a[i][j];
return *this;
}
};
Matrix a, b, c;
Matrix Mul(const Matrix& x, const Matrix& y)
{
Matrix s;
for (register int i = 1; i <= N; ++i)
for (register int j = 1; j <= N; ++j)
s.a[i][j] = 0;
for (register int k = 1; k <= N; ++k)
for (register int i = 1; i <= N; ++i)
for (register int j = 1; j <= N; ++j)
s.a[i][j] = (s.a[i][j] + (ll)x.a[i][k] * y.a[k][j] % mod) % mod;
return s;
}
Matrix _pow(Matrix x, int y)
{
Matrix s;
for (register int i = 1; i <= N; ++i)
for (register int j = 1; j <= N; ++j)
s.a[i][j] = (i == j);
for (; y; y >>= 1, x = Mul(x, x)) if (y & 1) s = Mul(s, x);
return s;
}
int main()
{
N = 2;
scanf("%d", &n);
c.a[1][1] = 0; c.a[1][2] = 1;
a.a[2][1] = a.a[1][2] = 1; a.a[2][2] = 2;
if (n <= 1) {printf("%d
", c.a[1][n + 1]); return 0; }
b = Mul(c, _pow(a, n - 1));
printf("%d
", b.a[1][2]);
}