2022 GDCPC K 斐波那契 基于分块矩阵和转普通矩阵的两种实现

一个使用赛时数据的补题链接:这里

官方题解讲的很清晰,解题思路直接看题解。我只看了解法一,所以只给解法一的实现。这里直接给出题解的实现代码。

在这里插入图片描述

分块矩阵

矩阵每个元素是矩阵或元素,考虑使用模板类。表现:

在这里插入图片描述

p.s. 锦乐是我的一个小号

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll mod = 998244353;
struct integer
{
    ll v;
    integer() : v(0) {}
    integer(ll x) : v(x) {}
    friend integer operator+(const integer &a, const integer &b) { return integer((a.v + b.v) % mod); }
    friend integer operator*(const integer &a, const integer &b) { return integer(a.v * b.v % mod); }
    friend ostream &operator<<(ostream &os, const integer &i)
    {
        os << i.v;
        return os;
    }
};
template <class t>
struct matrix
{
    vector<vector<t>> a;
    ll n;
    matrix(const vector<vector<t>> &aa) : a(aa), n(aa.size()) {}
    matrix(int nn = 2) : n(nn)
    {
        a = vector<vector<t>>(n, vector<t>(n));
    }
    friend matrix<t> operator+(const matrix<t> &x, const matrix<t> &y)
    {
        matrix<t> r = matrix<t>(x.n);
        for (ll i = 0; i < x.n; ++i)
        {
            for (ll j = 0; j < x.n; ++j)
            {
                r.a[i][j] = x.a[i][j] + y.a[i][j];
            }
        }
        return r;
    }
    friend matrix<t> operator*(const matrix<t> &x, const matrix<t> &y)
    {
        matrix<t> r = matrix<t>(x.n);
        for (ll i = 0; i < x.n; ++i)
        {
            for (ll j = 0; j < x.n; ++j)
            {
                for (ll k = 0; k < x.n; ++k)
                {
                    r.a[i][j] = r.a[i][j] + x.a[i][k] * y.a[k][j];
                }
            }
        }
        return r;
    }
    matrix<t> pow(ll k)
    {
        if (k == 0)
        {
            return matrix<t>(n);
        }
        if (k == 1)
        {
            return *this;
        }
        if (k % 2 == 1)
        {
            return *this * pow(k - 1);
        }
        matrix<t> r = pow(k / 2);
        return r * r;
    }
    friend ostream &operator<<(ostream &os, const matrix<t> &m)
    {
        for (ll i = 0; i < m.n; ++i)
        {
            for (ll j = 0; j < m.n; ++j)
            {
                os << m.a[i][j] << ' ';
            }
            os << '\n';
        }
        return os;
    }
};
using arr = vector<vector<integer>>;
using mat = matrix<integer>;
mat unit(ll v)
{
    return mat(arr{
        {v == 0 ? 0 : 1, v}, {0, v == 0 ? 0 : 1}});
}
using arr2 = vector<vector<mat>>;
using mat2 = matrix<mat>;
mat fib(ll k)
{
    mat m = mat(arr{{0, 1}, {1, 1}});
    return m.pow(k);
}

const ll mn = 52;
ll n, m, k, e[mn][mn];
signed main()
{
    // freopen("3.in", "r", stdin);
    // freopen("3.out", "w", stdout);
    ios::sync_with_stdio(false), cin.tie(0);
    cin >> n >> m >> k;
    arr2 ve = arr2(n, vector<mat>(n));
    for (ll u, v, w; m--;)
    {
        cin >> u >> v >> w;
        --u, --v;
        ve[u][v] = ve[u][v] + fib(w);
    }
    mat2 m = mat2(ve);
    m = m.pow(k);
    auto print = [&](mat2 m)
    {
        for (ll i = 0; i < n; ++i)
        {
            for (ll j = 0; j < n; ++j)
            {
                cout << m.a[i][j].a[0][1] << ' ';
            }
            cout << '\n';
        }
    };
    print(m);
    return 0;
}
/*
3 5 5
1 2 1
2 1 2
1 1 3
3 3 1
2 3 4
*/
普通矩阵

按照题解转化为 2 n × 2 n 2n\times 2n 2n×2n 矩阵。表现:

在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll mod = 998244353;
using arr = vector<vector<ll>>;
struct matrix
{
    ll n;
    arr a;
    matrix(ll nn = 2) : n(nn)
    {
        a = arr(n, vector<ll>(n));
    }

    matrix(arr aa) : n(aa.size()), a(aa) {}
    friend matrix operator+(const matrix &x, const matrix &y)
    {
        matrix r = matrix(x.n);
        for (ll i = 0; i < x.n; ++i)
        {
            for (ll j = 0; j < x.n; ++j)
            {
                r.a[i][j] = (x.a[i][j] + y.a[i][j]) % mod;
            }
        }
        return r;
    }
    friend matrix operator*(const matrix &x, const matrix &y)
    {
        matrix r = matrix(x.n);
        for (ll i = 0; i < x.n; ++i)
        {
            for (ll j = 0; j < x.n; ++j)
            {
                for (ll k = 0; k < x.n; ++k)
                {
                    r.a[i][j] = (r.a[i][j] + x.a[i][k] * y.a[k][j]) % mod;
                }
            }
        }
        return r;
    }
    matrix pow(ll k)
    {
        if (k == 0)
        {
            return matrix(n);
        }
        if (k == 1)
        {
            return *this;
        }
        if (k % 2 == 1)
        {
            return *this * pow(k - 1);
        }
        matrix r = pow(k / 2);
        return r * r;
    }
};
using mat = matrix;
mat fib(ll k)
{
    mat m = mat({{0, 1}, {1, 1}});
    return m.pow(k);
}
ll n, m, k;
signed main()
{
    ios::sync_with_stdio(false), cin.tie(0);
    cin >> n >> m >> k;
    mat e = mat(n * 2);
    for (ll u, v, w; m--;)
    {
        cin >> u >> v >> w;
        --u, --v;
        mat f = fib(w);
        (e.a[u * 2][v * 2] += f.a[0][0]) %= mod;
        (e.a[u * 2][v * 2 + 1] += f.a[0][1]) %= mod;
        (e.a[u * 2 + 1][v * 2] += f.a[1][0]) %= mod;
        (e.a[u * 2 + 1][v * 2 + 1] += f.a[1][1]) %= mod;
    }
    e = e.pow(k);
    for (ll i = 0; i < n; ++i)
    {
        for (ll j = 0; j < n; ++j)
        {
            cout << e.a[2 * i][2 * j + 1] << ' ';
        }
        cout << '\n';
    }
    return 0;
}
/*
3 5 5
1 2 1
2 1 2
1 1 3
3 3 1
2 3 4
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值