CF1117D - Magic Gems (矩阵快速幂)

Description

题目大意是,一个魔法宝石可以分裂成M个普通宝石。你有若干个魔法宝石,问你生成N个宝石(包括魔法和普通宝石)的有多少种情况。

思路

设f[N]为生成N个宝石的方案数,它可以来自N-1个宝石加一个魔法宝石,或N-M个宝石加M个普通宝石(由一个魔法宝石分裂而来)。
所以可以得到递推式:
f[N] = f[N - M] + f[N - 1]
f[0] = f[1] = 1
f[n] = 0 (n < 0)
然后就可以用矩阵快速幂求了。
如何列相应矩阵,可以见我之前的一篇文章

const int N = 1e3 + 10;
const int M = 1000000007;
const double eps = 1e5;
 
ll f[N];
 
ll init(ll n, ll m) {
    if(n == 1 || n == 0) {
        return f[1] = 1;
    }
    if(n < 1) return 0;
    if(f[n]) return f[n];
    return f[n] = (init(n - 1, m) + init(n - m, m)) % M;
}
 
ll A[N][N];
ll B[N][N];
ll tmp[N][N];
 
void mul1(int n) {
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) {
            tmp[i][j] = 0;
            for(int k = 1; k <= n; k++) {
                tmp[i][j] += A[i][k] * B[k][j];
                tmp[i][j] %= M;
            }
        }
    }
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) {
            B[i][j] = tmp[i][j];
        }
    }
}
 
void mul2(int n) {
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) {
            tmp[i][j] = 0;
            for(int k = 1; k <= n; k++) {
                tmp[i][j] += A[i][k] * A[k][j];
                tmp[i][j] %= M;
            }
        }
    }
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) {
            A[i][j] = tmp[i][j];
        }
    }
}
 
void qpow(ll n, int m) {
    while(n) {
        if(n & 1) {
            mul1(m);      //B = B * A
        }
        mul2(m);          //A = A * A
        n = n >> 1;
    }
}
 
 
int main() {
    IOS;
    ll n, m;
    cin >> n >> m;
    init(m, m);
    for(int i = 1; i <= m; i++) {
        B[i][i] = 1;
    }
    A[1][1] = 1;
    A[1][m] = 1;
    for(int i = 1; i < m; i++) A[i + 1][i] = 1;
    if(n <= m) {
        cout << f[n] << endl;
    } else {
        qpow(n - m, m);
        ll ans = 0;
        for(int i = 1; i <= m; i++) {
            ans = (ans + B[1][i] * f[m - i + 1]) % M;
        }
        cout << ans << endl;
    }
}
posted @ 2020-06-04 09:37  limil  阅读(115)  评论(0编辑  收藏  举报