CF166E-Tetrahedron

13 阅读6分钟

CF166E-Tetrahedron

题目大意

你有一个四面体,每一步你可以从上面某一点经由一条边,走到其他三点中一点。询问你经过 nn 步后有多少种可能回到初始点的走法。

题解

可以通过矩阵快速幂加速,一个表示边连通性的邻接表,矩阵快速幂 nn 次后,即表示 nn 步后从某一点到达另一点的路径数量。

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