一、题目
垒骰子
赌圣atm晚年迷恋上了垒骰子,就是把骰子一个垒在另一个上边,不能歪歪扭扭,要垒成方柱体。
经过长期观察,atm 发现了稳定骰子的奥秘:有些数字的面贴着会互相排斥!
我们先来规范一下骰子:1 的对面是 4,2 的对面是 5,3 的对面是 6。
假设有 m 组互斥现象,每组中的那两个数字的面紧贴在一起,骰子就不能稳定的垒起来。
atm想计算一下有多少种不同的可能的垒骰子方式。
两种垒骰子方式相同,当且仅当这两种方式中对应高度的骰子的对应数字的朝向都相同。
由于方案数可能过多,请输出模 10^9 + 7 的结果。
不要小看了 atm 的骰子数量哦~
「输入格式」
第一行两个整数 n m
n表示骰子数目
接下来 m 行,每行两个整数 a b ,表示 a 和 b 数字不能紧贴在一起。
「输出格式」
一行一个数,表示答案模 10^9 + 7 的结果。
「样例输入」
2 1
1 2
「样例输出」
544
「数据范围」
对于 30% 的数据:n <= 5
对于 60% 的数据:n <= 100
对于 100% 的数据:0 < n <= 10^9, m <= 36
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 2000ms
二、思路
假设$d[i]$表示第$n$层以数字$i$朝上的色子摆放方案数(先不考虑四周的朝向),那么,一开始,$d[] = {0, 1, 1, 1, 1, 1, 1}$。同时,还有一个矩阵$f$,$f[i][j]$表示第$n-1$层的色子以$i$朝上、第$n$层的色子以$j$朝上是否可行。也就是说,如果数字$a$和$b$冲突,那么,$f[a][op[b]] = 0$(当然,也有$f[b][op[a]]=0$);如果数字x和y不冲突,那么,$f[x][op[y]] = 1$(当然,也有$f[y][op[x]]=1$)。其中,$op[x]$表示与数字$x$对立的数字。如,$op[1] = 4$,整个$op$数组的值为:$op[] = \{0, 4, 5, 6, 1, 2, 3\}$。
由上可知(这句话其实都是忽悠人的,使语言表达起来逻辑连贯性更强而已。其实说白了就是凭感觉),
当$n = 1$时,结果为$6(6种朝上的数字) * 4(每种朝上的数字周围的数字都有4种朝向) = 24$。
当$n > 1$时,第$2$层各面朝上的方案数为:\[d = d * f * 4^2\] \[ans = \sum\limits_{i=1}^{6}d_i % 10^9+7\]
第$3$层各面朝上的方案数为:\[d = d * f^2 * 4^3\] \[ans = \sum\limits_{i=1}^{6}d_i % 10^9+7\]
……
第$n$层各面朝上的方案数为:\[d = d * f^{n-1} * 4^n\] \[ans = \sum\limits_{i=1}^{6}d_i % 10^9+7\]
所以,只要求出$f^{n-1}$和$4^n$,那么,问题就解决了。而这可以使用(矩阵)快速幂求解。
三、源代码
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> using namespace std; #define MOD 1000000007 typedef long long LL; typedef vector<LL> vec1d; typedef vector<vec1d> Matrix; , , , , , , }; , , , , , , }; Matrix mul(Matrix& a, Matrix& b) { Matrix c(, vec1d()); ; i < a.size(); ++i) { ; j < b.size(); ++j) { ; k < b[].size(); ++k) { c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % MOD; } } } return c; } Matrix mpow(Matrix a, LL x) { Matrix res(, vec1d()); ; i <= ; ++i)res[i][i] = ; ) { )res = mul(res, a); a = mul(a, a); x >>= ; } return res; } LL iqow(LL a, LL x) { LL res = ; ) { )res = (res * a) % MOD; a = (a * a) % MOD; x >>= ; } return res; } int main() { #ifndef ONLINE_JUDGE //freopen("input.txt", "r", stdin); //freopen("output2.txt", "w", stdout); #endif // ONLINE_JUDGE LL n, m, a, b; scanf("%I64d%I64d", &n, &m); Matrix f(, vec1d()); ; i <= ; ++i); j <= ; ++j)f[i][j] = ; ; i < m; ++i) { scanf("%I64d%I64d", &a, &b); f[a][op[b]] = , f[b][op[a]] = ; } )printf("24\n"); else { f = mpow(f, n - ); LL ans = ; ; i <= ; ++i)ans = (accumulate(f[i].begin() + , f[i].end(), 0LL) + ans) % MOD; printf(, n)) % MOD); } ; }