1256: [藍橋杯2015初賽]壘骰子
阿新 • • 發佈:2020-07-30
題目描述
賭聖atm晚年迷戀上了壘骰子,就是把骰子一個壘在另一個上邊,不能歪歪扭扭,要壘成方柱體。經過長期觀察,atm 發現了穩定骰子的奧祕:有些數字的面貼著會互相排斥!
我們先來規範一下骰子:1 的對面是 4,2 的對面是 5,3 的對面是 6。
假設有 m 組互斥現象,每組中的那兩個數字的面緊貼在一起,骰子就不能穩定的壘起來。
atm想計算一下有多少種不同的可能的壘骰子方式。
兩種壘骰子方式相同,當且僅當這兩種方式中對應高度的骰子的對應數字的朝向都相同。
由於方案數可能過多,請輸出模 10^9 + 7 的結果。
輸入
輸入存在多組測試資料,對於每組資料:第一行兩個整數 n m(0<n<10^9,m<=36)
接下來 m 行,每行兩個整數 a b ,表示 a 和 b 數字不能緊貼在一起。
輸出
對於每組測試資料,輸出一行,只包含一個數,表示答案模 10^9 + 7 的結果。樣例輸入Copy
2 1
1 2
樣例輸出 Copy
544
#include <iostream> #include <map> using namespace std; typedef long long ll; const int mod = 1e9 + 7; int n, m; map<int, int > op; void init(){ op[1] = 4; op[2] = 5; op[3] = 6; op[4] = 1; op[5] = 2; op[6] = 3; } struct M{ ll a[7][7]; M () { for (int i = 1; i <= 6; i ++ ) for (int j = 1; j <= 6; j ++ ) a[i][j] = 1; } }; M Multiply(M s, M t){ M ans; for (int i = 1; i <= 6; i ++ ) for (int j = 1; j <= 6; j ++ ){ ans.a[i][j] = 0; for (int k = 1; k <= 6; k ++ ) ans.a[i][j] = (ans.a[i][j] + s.a[i][k] * t.a[k][j]) % mod; } return ans; } M mpow(M m, int k){//矩陣m的k次方 M ans;//ans開始的時候,是一個單位矩陣 for (int i = 1; i <= 6; i ++ ) for (int j = 1; j <= 6; j ++ ) if (i == j) ans.a[i][j] = 1;//對角線為1 else ans.a[i][j] = 0;//其餘地方為0 while (k){ if (k & 1) ans = Multiply(ans, m); k >>= 1; m = Multiply(m, m); } return ans; } ll fun(int a, int b){ ll res = 1; while (b){ if (b & 1) res = res * a % mod; b >>= 1; a = a * a; } return res; } int main(){ init(); scanf("%d%d", &n, &m); M cf; for (int i = 0; i < m; i ++ ){ int a, b; scanf("%d%d", &a, &b); cf.a[op[a]][b] = 0; cf.a[op[b]][a] = 0; } M mp = mpow(cf, n - 1); ll res = 0; for (int i = 1; i <= 6; i ++ ) for (int j = 1; j <= 6; j ++ ) res =(res + mp.a[i][j]) % mod; printf("%lld\n", res * fun(4, n) % mod); return 0; }