hdu6030 Happy Necklace(递推转矩阵快速幂)

题目链接: hdu6030 ( Happy Necklace )

每一个素数长度的序列中红色个数不少于蓝色,等价于每 \(2\) 个珠子至少一个红色、每 \(3\) 个珠子两个红色,其余素数均可拆为一系列 \(2\)\(3\) 的和。

\(f_n\) 代表含 \(n\) 个珠子的种类数,

\(n\) 个珠子为红色时,第 \(n-1\) 个珠子的颜色可任取,有 \(f_{n-1}\) 种。

\(n\) 个珠子为蓝色时,第 \(n-1\)\(n-2\) 个珠子必取红色,第 \(n-3\) 个珠子颜色任取,有 \(f_{n-3}\) 种。

因此, \(f_n=f_{n-1}+f_{n-3}\)

由于数据范围很大,需先将递推关系转化为矩阵运算,再用矩阵快速幂求得。

由于

\[\begin{align} f_{i+2} &= 1\cdot f_{i+1} + 0\cdot f_{i} + 1\cdot f_{i-1}\\ f_{i+1} &= 1\cdot f_{i+1} + 0\cdot f_{i} + 0\cdot f_{i-1}\\ f_{i} &= 0\cdot f_{i+1} + 1\cdot f_{i} + 0\cdot f_{i-1} \end{align} \]

\(A=\begin{pmatrix}1&0&1\\ 1&0&0\\ 0&1&0\end{pmatrix}\)

\[\Rightarrow \begin{pmatrix} f_{i+2}\\ f_{i+1}\\ f_i \end{pmatrix} =A\cdot \begin{pmatrix}f_{i+1}\\ f_{i}\\ f_{i-1} \end{pmatrix} =A^i\cdot \begin{pmatrix}f_{2}\\ f_{1}\\ f_{0} \end{pmatrix} \]

\(AC\) 代码:

/**
 * hdu6030 Happy Necklace
 *
 */

#include <iostream>
#include <climits>
#include <vector>
#include <cmath>
#include <iomanip>
using namespace std;

typedef long long LL;

struct Matrix
{
    vector<vector<LL> > m;
    Matrix(int row, int col)
    {
        m.resize(row, vector<LL>(col));
    }
    Matrix mul(const Matrix &t, const LL mod = LLONG_MAX)
    {
        int row = m.size(), col = t.m[0].size(), cnt = m[0].size();
        Matrix res(row, col);
        for (int i = 0; i < row; ++i) {
            for (int j = 0; j < col; ++j) {
                for (int k = 0; k < cnt; ++k) {
                    res.m[i][j] += m[i][k]*t.m[k][j]%mod;
                    res.m[i][j] %= mod;
                }
            }
        }
        return res;
    }
    Matrix pow(LL n, const LL mod = LLONG_MAX)
    {
        int sz = m.size();
        Matrix a = *this, t(sz, sz);
        for (int i = 0; i < sz; ++i) t.m[i][i] = 1;
        while (n) {
            if (n&1) t = t.mul(a, mod);
            a = a.mul(a, mod);
            n >>= 1;
        }
        return t;
    }
};

const int mod = 1e9+7;

int main()
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    Matrix A(3, 3), m0(3, 1);
    A.m[0][0] = A.m[0][2] = A.m[1][0] = A.m[2][1] = 1;
    m0.m[2][0] = 1, m0.m[1][0] = 2, m0.m[0][0] = 3;

    int T;
    cin >> T;
    while (T--) {
        LL n;
        cin >> n;
        cout << A.pow(n, mod).mul(m0, mod).m[2][0] << endl;
    }
    return 0;
}

上述代码 \(998ms\) 险过,经测试,主要耗时在 \(vector\) ,将存储矩阵的 \(vector\) 换成 LL m[3][3]\(156ms\) \(AC\)

模板总结

结构体 \(Matrix\) 含成员方法:乘法取模 \(mul\) ,快速幂取模 \(pow\)

struct Matrix
{
    vector<vector<LL> > m;  // vector有TLE风险
    Matrix(int row, int col)
    {
        m.resize(row, vector<LL>(col));
    }
    Matrix mul(const Matrix &t, const LL mod = LLONG_MAX)
    {
        int row = m.size(), col = t.m[0].size(), cnt = m[0].size();
        Matrix res(row, col);
        for (int i = 0; i < row; ++i)
            for (int j = 0; j < col; ++j)
                for (int k = 0; k < cnt; ++k)
                    res.m[i][j] += m[i][k]*t.m[k][j]%mod,
                    res.m[i][j] %= mod;
        return res;
    }
    Matrix pow(LL n, const LL mod = LLONG_MAX)
    {
        int sz = m.size();
        Matrix a = *this, t(sz, sz);
        for (int i = 0; i < sz; ++i) t.m[i][i] = 1;
        while (n) {
            if (n&1) t = t.mul(a, mod);
            a = a.mul(a, mod);
            n >>= 1;
        }
        return t;
    }
};
posted @ 2021-02-02 17:57  Zewbie  阅读(54)  评论(0)    收藏  举报