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;
}
};