垒骰子(矩阵快速幂)

垒骰子

题目描述

赌圣atm晚年迷恋上了垒骰子,就是把骰子一个垒在另一个上边,不能歪歪扭扭,要垒成方柱体。
经过长期观察,atm 发现了稳定骰子的奥秘:有些数字的面贴着会互相排斥!
我们先来规范一下骰子:1 的对面是 4,2 的对面是 5,3 的对面是 6。
假设有 m 组互斥现象,每组中的那两个数字的面紧贴在一起,骰子就不能稳定的垒起来。
atm想计算一下有多少种不同的可能的垒骰子方式。
两种垒骰子方式相同,当且仅当这两种方式中对应高度的骰子的对应数字的朝向都相同。
由于方案数可能过多,请输出模 10^9 + 7 的结果。

输入

输入存在多组测试数据,对于每组数据:
第一行两个整数 n m(0 n表示骰子数目
接下来 m 行,每行两个整数 a b ,表示 a 和 b 数字不能紧贴在一起。

输出

对于每组测试数据,输出一行,只包含一个数,表示答案模 10^9 + 7 的结果。

样例输入

2 1
1 2

样例输出

544

题解

不是很难的题目,就是比较难想到去用矩阵快速幂去做,还是做题太少,网上的代码有很多太乱,我按自己的模板写了一下,点击题目有 OJ 去练习,比原题稍微改了一下,多了几组测试样例,另,网上的代码在上面测试可能会有误。

代码实现
#include 
#include 
#include 
#include 
#include 

#define ll long long
using namespace std;
const ll mod = 1e9 + 7;
ll n, m;
struct Matrix {
    ll v[6][6];
};

ll QuickPow(ll x, ll N) {
    ll res = x;
    ll ans = 1;
    while (N) {
        if (N & 1) {
            ans = ans * res % mod;
        }
        res = res * res % mod;
        N = N >> 1;
    }
    return ans % mod;
}

Matrix mul(Matrix a, Matrix b, int rank) {
    Matrix tmp;
    memset(tmp.v, 0, sizeof(tmp.v));
    for (int i = 0; i < rank; i++) {
        for (int j = 0; j < rank; j++) {
            for (int k = 0; k < rank; k++) {
                tmp.v[i][j] = (tmp.v[i][j] + a.v[i][k] * b.v[k][j] % mod) % mod;
            }
        }
    }
    return tmp;
}

Matrix QuickPower(Matrix res, ll N, int rank) {
    Matrix ans;
    for (int i = 0; i < rank; i++) {
        for (int j = 0; j < rank; j++) {
            ans.v[i][j] = (i == j);
        }
    }
    while (N) {
        if (N & 1) {
            ans = mul(ans, res, rank);
        }
        res = mul(res, res, rank);
        N = N >> 1;
    }
    return ans;
}

int main() {
    while (cin >> n >> m) {
        Matrix res, ans;
        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 6; j++) {
                res.v[i][j] = 1;
            }
        }
        for (int i = 0; i < m; i++) {
            int a, b;
            cin >> a >> b;
            a--;
            b--;
            res.v[a][(b + 3) % 6] = res.v[b][(a + 3) % 6] = 0;
        }
        ans = QuickPower(res, n - 1, 6);
        ll a1 = QuickPow(4, n);
        ll sum = 0;
        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 6; j++) {
                sum = (sum + ans.v[i][j]) % mod;
            }
        }
        cout << (sum * a1) % mod << endl;
    }
    return 0;
}

你可能感兴趣的:(数学)