1. 程式人生 > >洛谷 P4451 [國家集訓隊]整數的lqp拆分

洛谷 P4451 [國家集訓隊]整數的lqp拆分

題意簡述

\(F_{x}\)為斐波那契數列第\(x\)
將一個數\(n\)拆分為\(a{1}, a{2}, ..., a{m}\), 即\(a{1} + a{2} +...+ a{m} = n\)
求\(\sum\prod\limits_{i =1}^m F_{a_i}\)

題解

遞推
\(g(i)\)為當n = i時的答案
所以
\(g(i) = \sum\limits_{j = 1} ^ {i - 1} g(j) * F_{i - j} + F_i\)
\(g(i + 1) = \sum\limits_{j = 1} ^ {i} g(j) * F_{i + 1 - j} + F_{i + 1}\)


\(g(i + 1) - g(i)\)
$ = \sum\limits_{j = 1} ^ {i - 1} g(j) * (F_{i + 1 - j} - F_{i - j}) + g(i) * F_1 + F_{i + 1} - F_i$
$ = \sum\limits_{j = 1} ^ {i - 1} g(j) * F_{i - j - 1} + g(i) + F_{i - 1}$
$ = \sum\limits_{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\n", c.a[1][n + 1]); return 0; }
    b = Mul(c, _pow(a, n - 1));
    printf("%d\n", b.a[1][2]);
}