【矩阵快速幂优化DP】【校内测试】

实际上是水水题叻,先把朴素DP方程写出来,发现$dp[i]$实际上是$dp[i-k]-dp[i-1]$的和,而看数据范围,我们实际上是要快速地求得这段的和,突然就意识到是矩阵快速幂叻。

构建矩阵什么的还是很简单滴,主要就是练一练手。

(还有就是水一水blog!换个字体,换个心情!

(快速乘是在模数很大时要用,避免超long long

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define mod 7777777

LL k, n, dp[11];

struct Matrix {
    LL w[11][11];
} base;

struct Node {
    LL w[11][2];
} pool;

Matrix Cheng(Matrix a, Matrix b) {
    Matrix ans;
    for(int i = 1; i <= k; i ++)
        for(int j = 1; j <= k; j ++)
            ans.w[i][j] = 0;
    for(int i = 1; i <= k; i ++)
        for(int j = 1; j <= k; j ++)
            for(int p = 1; p <= k; p ++)
                ans.w[i][j] = (ans.w[i][j] + a.w[i][p] * b.w[p][j] % mod) % mod;
    return ans;
}

Matrix mpow(Matrix a, LL b) {
    Matrix ans;
    for(int i = 1; i <= k; i ++)
        for(int j = 1; j <= k; j ++)
            if(i == j)    ans.w[i][j] = 1;
            else    ans.w[i][j] = 0;
    for(; b; b >>= 1, a = Cheng(a, a))
        if(b & 1) ans = Cheng(ans, a);
    return ans;
}

int main() {
    freopen("fyfy.in", "r", stdin);
    freopen("fyfy.out", "w", stdout);
    scanf("%lld%lld", &k, &n);
    for(int i = 1; i <= k; i ++)
        for(int j = 1; j <= k; j ++)    base.w[i][j] = 0;
    for(int i = 1; i <= k; i ++)    base.w[1][i] = 1;
    for(int i = 2; i <= k; i ++)    base.w[i][i-1] = 1;
    dp[0] = 1;
    for(int i = 1; i <= k; i ++)
        for(int j = 1; j <= i; j ++)
            dp[i] = (dp[i] + dp[i-j]) % mod;
    for(int i = 1; i <= k; i ++)    pool.w[i][1] = dp[k-i+1];
    base = mpow(base, n-k);
    LL ans = 0;
    for(int i = 1; i <= k; i ++)    ans = (ans + base.w[1][i] * pool.w[i][1] % mod) % mod;
    printf("%lld", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/wans-caesar-02111007/p/9687692.html