题目大意
你有一个四面体,每一步你可以从上面某一点经由一条边,走到其他三点中一点。询问你经过 步后有多少种可能回到初始点的走法。
题解
可以通过矩阵快速幂加速,一个表示边连通性的邻接表,矩阵快速幂 次后,即表示 步后从某一点到达另一点的路径数量。
#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define umap unordered_map
#define pq(x) priority_queue<x>
#define ppq(x) priority_queue<x,vector<x>,greater<x>>
#define endl '\n'
using namespace std;
using i128 = __int128;
const int mod =1e9+7;
template <typename T>void read(T&x){
x=0;int f = 1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+(c^48);
x*=f;
}
template <typename T>void print(T x) {
if (x < 0) { putchar('-'); x = -x; }
if (x > 9) print(x / 10);
putchar(x % 10 + '0');
}
template<typename T>
struct Matrix {
size_t rows, cols;
std::vector<std::vector<T>> data;
// 默认构造函数
Matrix() : rows(0), cols(0) {}
// 构造函数
Matrix(size_t r, size_t c) : rows(r), cols(c) {
data.resize(rows, std::vector<T>(cols, T{}));
}
Matrix(size_t r, size_t c, const T& value) : rows(r), cols(c) {
data.resize(rows, std::vector<T>(cols, value));
}
// 从二维向量构造
Matrix(const std::vector<std::vector<T>>& matrix) {
if (matrix.empty() || matrix[0].empty()) {
throw std::invalid_argument("矩阵不能为空");
}
rows = matrix.size();
cols = matrix[0].size();
data = matrix;
}
};
// 访问元素
template<typename T>
T& matrixAt(Matrix<T>& matrix, size_t row, size_t col) {
if (row >= matrix.rows || col >= matrix.cols) {
throw std::out_of_range("矩阵索引越界");
}
return matrix.data[row][col];
}
template<typename T>
const T& matrixAt(const Matrix<T>& matrix, size_t row, size_t col) {
if (row >= matrix.rows || col >= matrix.cols) {
throw std::out_of_range("矩阵索引越界");
}
return matrix.data[row][col];
}
// 矩阵加法
template<typename T>
Matrix<T> matrixAdd(const Matrix<T>& a, const Matrix<T>& b) {
if (a.rows != b.rows || a.cols != b.cols) {
throw std::invalid_argument("矩阵维度不匹配,无法相加");
}
Matrix<T> result(a.rows, a.cols);
for (size_t i = 0; i < a.rows; ++i) {
for (size_t j = 0; j < a.cols; ++j) {
matrixAt(result, i, j) = a.data[i][j] + b.data[i][j];
}
}
return result;
}
// 矩阵减法
template<typename T>
Matrix<T> matrixSub(const Matrix<T>& a, const Matrix<T>& b) {
if (a.rows != b.rows || a.cols != b.cols) {
throw std::invalid_argument("矩阵维度不匹配,无法相减");
}
Matrix<T> result(a.rows, a.cols);
for (size_t i = 0; i < a.rows; ++i) {
for (size_t j = 0; j < a.cols; ++j) {
matrixAt(result, i, j) = a.data[i][j] - b.data[i][j];
}
}
return result;
}
// 矩阵乘法
template<typename T>
Matrix<T> matrixMul(const Matrix<T>& a, const Matrix<T>& b) {
if (a.cols != b.rows) {
throw std::invalid_argument("矩阵维度不匹配,无法相乘");
}
Matrix<T> result(a.rows, b.cols);
for (size_t i = 0; i < a.rows; ++i) {
for (size_t j = 0; j < b.cols; ++j) {
T sum = T{};
for (size_t k = 0; k < a.cols; ++k) {
sum += a.data[i][k] * b.data[k][j];
}
matrixAt(result, i, j) = sum;
}
}
return result;
}
// 标量乘法
template<typename T>
Matrix<T> matrixScalarMul(const Matrix<T>& matrix, const T& scalar) {
Matrix<T> result(matrix.rows, matrix.cols);
for (size_t i = 0; i < matrix.rows; ++i) {
for (size_t j = 0; j < matrix.cols; ++j) {
matrixAt(result, i, j) = matrix.data[i][j] * scalar;
}
}
return result;
}
// 标量除法
template<typename T>
Matrix<T> matrixScalarDiv(const Matrix<T>& matrix, const T& scalar) {
if (scalar == T{}) {
throw std::invalid_argument("除数不能为零");
}
Matrix<T> result(matrix.rows, matrix.cols);
for (size_t i = 0; i < matrix.rows; ++i) {
for (size_t j = 0; j < matrix.cols; ++j) {
matrixAt(result, i, j) = matrix.data[i][j] / scalar;
}
}
return result;
}
// 矩阵转置
template<typename T>
Matrix<T> matrixTranspose(const Matrix<T>& matrix) {
Matrix<T> result(matrix.cols, matrix.rows);
for (size_t i = 0; i < matrix.rows; ++i) {
for (size_t j = 0; j < matrix.cols; ++j) {
matrixAt(result, j, i) = matrix.data[i][j];
}
}
return result;
}
// 判断是否为方阵
template<typename T>
bool isSquare(const Matrix<T>& matrix) {
return matrix.rows == matrix.cols;
}
// 判断是否为对称矩阵
template<typename T>
bool isSymmetric(const Matrix<T>& matrix) {
if (!isSquare(matrix)) return false;
for (size_t i = 0; i < matrix.rows; ++i) {
for (size_t j = 0; j < matrix.cols; ++j) {
if (matrix.data[i][j] != matrix.data[j][i]) {
return false;
}
}
}
return true;
}
// 判断是否为单位矩阵
template<typename T>
bool isIdentity(const Matrix<T>& matrix) {
if (!isSquare(matrix)) return false;
for (size_t i = 0; i < matrix.rows; ++i) {
for (size_t j = 0; j < matrix.cols; ++j) {
if (i == j && matrix.data[i][j] != T{1}) {
return false;
}
if (i != j && matrix.data[i][j] != T{}) {
return false;
}
}
}
return true;
}
// 获取子矩阵(用于计算行列式)
template<typename T>
Matrix<T> getMinor(const Matrix<T>& matrix, size_t row, size_t col) {
Matrix<T> minor(matrix.rows - 1, matrix.cols - 1);
size_t minorRow = 0, minorCol = 0;
for (size_t i = 0; i < matrix.rows; ++i) {
if (i == row) continue;
minorCol = 0;
for (size_t j = 0; j < matrix.cols; ++j) {
if (j == col) continue;
matrixAt(minor, minorRow, minorCol) = matrix.data[i][j];
minorCol++;
}
minorRow++;
}
return minor;
}
// 计算矩阵的行列式(仅适用于方阵)
template<typename T>
T matrixDeterminant(const Matrix<T>& matrix) {
if (!isSquare(matrix)) {
throw std::invalid_argument("只有方阵才能计算行列式");
}
if (matrix.rows == 1) {
return matrix.data[0][0];
}
if (matrix.rows == 2) {
return matrix.data[0][0] * matrix.data[1][1] - matrix.data[0][1] * matrix.data[1][0];
}
T det = T{};
for (size_t j = 0; j < matrix.cols; ++j) {
Matrix<T> minor = getMinor(matrix, 0, j);
T cofactor = (j % 2 == 0) ? matrixDeterminant(minor) : -matrixDeterminant(minor);
det += matrix.data[0][j] * cofactor;
}
return det;
}
// 计算矩阵的逆(仅适用于方阵且行列式不为零)
template<typename T>
Matrix<T> matrixInverse(const Matrix<T>& matrix) {
if (!isSquare(matrix)) {
throw std::invalid_argument("只有方阵才能计算逆矩阵");
}
T det = matrixDeterminant(matrix);
if (det == T{}) {
throw std::invalid_argument("矩阵不可逆(行列式为零)");
}
Matrix<T> adjugate(matrix.rows, matrix.cols);
for (size_t i = 0; i < matrix.rows; ++i) {
for (size_t j = 0; j < matrix.cols; ++j) {
Matrix<T> minor = getMinor(matrix, i, j);
T cofactor = ((i + j) % 2 == 0) ? matrixDeterminant(minor) : -matrixDeterminant(minor);
matrixAt(adjugate, j, i) = cofactor; // 注意这里是(j,i)而不是(i,j)
}
}
return matrixScalarDiv(adjugate, det);
}
// 计算矩阵的迹(对角线元素之和)
template<typename T>
T matrixTrace(const Matrix<T>& matrix) {
if (!isSquare(matrix)) {
throw std::invalid_argument("只有方阵才能计算迹");
}
T sum = T{};
for (size_t i = 0; i < matrix.rows; ++i) {
sum += matrix.data[i][i];
}
return sum;
}
// 计算矩阵的范数(Frobenius范数)
template<typename T>
T matrixNorm(const Matrix<T>& matrix) {
T sum = T{};
for (size_t i = 0; i < matrix.rows; ++i) {
for (size_t j = 0; j < matrix.cols; ++j) {
sum += matrix.data[i][j] * matrix.data[i][j];
}
}
return std::sqrt(sum);
}
// 创建单位矩阵
template<typename T>
Matrix<T> identityMatrix(size_t n) {
Matrix<T> result(n, n);
for (size_t i = 0; i < n; ++i) {
matrixAt(result, i, i) = T{1};
}
return result;
}
// 创建零矩阵
template<typename T>
Matrix<T> zeroMatrix(size_t rows, size_t cols) {
return Matrix<T>(rows, cols, T{});
}
// 创建全1矩阵
template<typename T>
Matrix<T> onesMatrix(size_t rows, size_t cols) {
return Matrix<T>(rows, cols, T{1});
}
// 矩阵快速幂
template<typename T>
Matrix<T> matrixPower(const Matrix<T>& matrix, long long n) {
if (!isSquare(matrix)) {
throw std::invalid_argument("只有方阵才能进行幂运算");
}
if (n < 0) {
throw std::invalid_argument("幂指数不能为负数");
}
if (n == 0) {
return identityMatrix<T>(matrix.rows);
}
Matrix<T> result = identityMatrix<T>(matrix.rows);
Matrix<T> base = matrix;
while (n > 0) {
if (n & 1) {
result = matrixMul(result, base);
}
base = matrixMul(base, base);
n >>= 1;
}
return result;
}
// 矩阵快速幂(带模运算)
template<typename T>
Matrix<T> matrixPowerMod(const Matrix<T>& matrix, long long n, long long mod) {
if (!isSquare(matrix)) {
throw std::invalid_argument("只有方阵才能进行幂运算");
}
if (n < 0) {
throw std::invalid_argument("幂指数不能为负数");
}
if (n == 0) {
return identityMatrix<T>(matrix.rows);
}
Matrix<T> result = identityMatrix<T>(matrix.rows);
Matrix<T> base = matrix;
// 对base进行模运算(只对整数类型有效)
if constexpr (std::is_integral_v<T>) {
for (size_t i = 0; i < base.rows; ++i) {
for (size_t j = 0; j < base.cols; ++j) {
matrixAt(base, i, j) = matrixAt(base, i, j) % mod;
}
}
}
while (n > 0) {
if (n & 1) {
result = matrixMul(result, base);
// 对结果进行模运算(只对整数类型有效)
if constexpr (std::is_integral_v<T>) {
for (size_t i = 0; i < result.rows; ++i) {
for (size_t j = 0; j < result.cols; ++j) {
matrixAt(result, i, j) = matrixAt(result, i, j) % mod;
}
}
}
}
base = matrixMul(base, base);
// 对base进行模运算(只对整数类型有效)
if constexpr (std::is_integral_v<T>) {
for (size_t i = 0; i < base.rows; ++i) {
for (size_t j = 0; j < base.cols; ++j) {
matrixAt(base, i, j) = matrixAt(base, i, j) % mod;
}
}
}
n >>= 1;
}
return result;
}
// 输出操作符
template<typename T>
std::ostream& operator<<(std::ostream& os, const Matrix<T>& matrix) {
for (size_t i = 0; i < matrix.rows; ++i) {
for (size_t j = 0; j < matrix.cols; ++j) {
os << std::setw(8) << std::fixed << std::setprecision(3)
<< matrix.data[i][j];
if (j < matrix.cols - 1) os << " ";
}
if (i < matrix.rows - 1) os << "\n";
}
return os;
}
// 输入操作符
template<typename T>
std::istream& operator>>(std::istream& is, Matrix<T>& matrix) {
for (size_t i = 0; i < matrix.rows; ++i) {
for (size_t j = 0; j < matrix.cols; ++j) {
is >> matrix.data[i][j];
}
}
return is;
}
// 标量乘法(左乘)
template<typename T>
Matrix<T> operator*(const T& scalar, const Matrix<T>& matrix) {
return matrixScalarMul(matrix, scalar);
}
#define int long long
const int N=5e5+5;
const int M=2e6+5;
vector<vector<int>> p={{0,1,1,1},{1,0,1,1},{1,1,0,1},{1,1,1,0}};
inline void solve()
{
int n;
cin>>n;
Matrix m(p);
Matrix ans=matrixPowerMod(m,n,1e9+7);
cout<<matrixAt(ans,0,0)<<endl;
}
signed main()
{
ios;
int T=1;
// cin>>T;
for(;T--;) solve();
return 0;
}