题目链接
动态规划 或 矩阵快速幂。
这个方法只能得到 78% 的分数,无法 AC,但确实比较好想。
笼统地说一下状态定义和转移方程。
dp[i][j]
表示从下向上数第i
个骰子的上面点数为j
的情况下,靠下的i
个骰子摆放的全部方案数。(这个定义不准确,后面会说)
那么转移方程可以比较容易地写出来了,第i
个骰子上面点数为1
,对应地其下面点数为4
,因此第i
个骰子上面点数为1
的方案数(即dp[i][1]
)为第i-1
个骰子上面点数不与第i
个骰子下面点数4
相排斥的情况数之和,即Σ{dp[i-1][k]}
,其中k
为不与4
排斥的点数;同理,dp[i][2]=Σ{dp[i-1][k]}
,其中k
为不与5
(即2
的对面点数)相排斥的点数;其他点数类似。
以样例为例,总共两个骰子,点数1
与点数2
排斥。
也就是说如果第二个骰子(从下向上数)上面点数为5
,换句话说就是第二个骰子的下面点数为2
,则第一个骰子上面的点数就不能为1
;如果第二个骰子上面点数为4
,则第二个骰子上面的点数不能为2
。
因此,
dp[2][1] = dp[1][1] + dp[1][2] + dp[1][3] + dp[1][4] + dp[1][5] + dp[1][6]
dp[2][2] = dp[1][1] + dp[1][2] + dp[1][3] + dp[1][4] + dp[1][5] + dp[1][6]
dp[2][3] = dp[1][1] + dp[1][2] + dp[1][3] + dp[1][4] + dp[1][5] + dp[1][6]
dp[2][4] = dp[1][1] + dp[1][3] + dp[1][4] + dp[1][5] + dp[1][6]
dp[2][5] = dp[1][2] + dp[1][3] + dp[1][4] + dp[1][5] + dp[1][6]
dp[2][6] = dp[1][1] + dp[1][2] + dp[1][3] + dp[1][4] + dp[1][5] + dp[1][6]
应该注意到“两种垒骰子方式相同,当且仅当这两种方式中对应高度的骰子的对应数字的朝向都相同”,也就是说,如果保证了某个骰子上面点数为1
,也就保证了其下面点数为4
,但是可以水平旋转0°、90°、180°或270°,也就是前后面和左右面的点数可以变化,这样也算不同的方案。
我们上面的对状态的定义很显然只保证了上下两面确定,也就是说我们错误地理解成了“两种垒骰子方式相同,当且仅当这两种方式中对应高度的骰子的上下两面的点数相同”。由于我们保证了上下两面不会出现排斥,所以只需要在此基础上水平方向上旋转骰子即可,每一个骰子确定的一种上下面都对应着四种情况(这句话的理解就是,如果某个骰子上下面的取值可能为:{1, 4} 、{3, 6} 和 {4, 1} ,那么按我们最初的理解只有该骰子只有三种摆放方式,但其实该骰子水平旋转是不影响上下面的,也就是不影响上下骰子的排斥关系的,所以我们可以尽情地旋转。{1, 4} 时,我们有四种旋转方法,{3, 6} 时,我们有四种旋转方法,{4, 1} 时,我们有四种旋转方法,因此总共12种方法,即3×4)。
这样一来,前i
层骰子总共具有(4^i)*(dp[i][1]+...+dp[i][6])
种摆法。
我们完全可以先按照最初对dp
的定义方式和转移方式去计算,最后再乘以4^n
即可。
矩阵快速幂基础讲解
首先根据上面对动态规划方法的理解,我们可以发现递推的转移方程:dp[i][j] = dp[i-1][k]
,k
为与abs(3-j)
不排斥的点数。
我们定义几个矩阵:
( d p [ i − 1 ] [ 1 ] d p [ i − 1 ] [ 2 ] d p [ i − 1 ] [ 3 ] d p [ i − 1 ] [ 4 ] d p [ i − 1 ] [ 5 ] d p [ i − 1 ] [ 6 ] ) \left( \begin{matrix} dp[i-1][1] \\ dp[i-1][2] \\ dp[i-1][3] \\ dp[i-1][4] \\ dp[i-1][5] \\ dp[i-1][6] \\ \end{matrix} \right) ⎝⎜⎜⎜⎜⎜⎜⎛dp[i−1][1]dp[i−1][2]dp[i−1][3]dp[i−1][4]dp[i−1][5]dp[i−1][6]⎠⎟⎟⎟⎟⎟⎟⎞
为了方便,我们给这个矩阵起名叫i-1
层矩阵 X i − 1 X_{i-1} Xi−1。
( d p [ i ] [ 1 ] d p [ i ] [ 2 ] d p [ i ] [ 3 ] d p [ i ] [ 4 ] d p [ i ] [ 5 ] d p [ i ] [ 6 ] ) \left( \begin{matrix} dp[i][1] \\ dp[i][2] \\ dp[i][3] \\ dp[i][4] \\ dp[i][5] \\ dp[i][6] \\ \end{matrix} \right) ⎝⎜⎜⎜⎜⎜⎜⎛dp[i][1]dp[i][2]dp[i][3]dp[i][4]dp[i][5]dp[i][6]⎠⎟⎟⎟⎟⎟⎟⎞
同理,这个就叫i
层矩阵 X i X_i Xi。
这俩矩阵具有什么关系呢?
由转移方程可知,第i
层矩阵的每个元素都可以表示成第i-1
层矩阵中的某些元素之和,而这些所谓的“某些”,正是第二维度为k
的那些元素。
还是以样例为例。
第1
层矩阵为: ( 1 1 1 1 1 1 ) \left(\begin{matrix}1 \\1 \\1 \\1 \\1 \\1 \\\end{matrix}\right) ⎝⎜⎜⎜⎜⎜⎜⎛111111⎠⎟⎟⎟⎟⎟⎟⎞,为了得到第2
层矩阵,我们需要让第1
层矩阵左乘一个 6 × 6 6×6 6×6的矩阵得到 6 × 1 6×1 6×1的第2
层矩阵(线性代数基础)。
假设 6 × 6 6×6 6×6的矩阵为 ( a 11 a 12 . . . a 16 a 21 a 22 . . . a 26 . . . . . . . . . a 61 a 62 . . . a 66 ) 6 × 6 \left(\begin{matrix}a_{11} & a_{12} & ... & a_{16} \\ a_{21} & a_{22} & ... & a_{26} \\ ...& ... &&... \\a_{61} & a_{62} & ... & a_{66}\\\end{matrix}\right)_{6×6} ⎝⎜⎜⎛a11a21...a61a12a22...a62.........a16a26...a66⎠⎟⎟⎞6×6,称为系数矩阵 A A A。
这个系数矩阵显然是由1
和0
构成的,即选或者不选。而且这个矩阵满足 A ∗ X i − 1 = X i A*X_{i-1}=X_i A∗Xi−1=Xi。
根据上述矩阵的定义和转移方程的含义,我们可以推算出系数矩阵的哪些位置为1
,哪些位置为0
。更直接点,上面不是写了一串dp[2][i] = ……
了嘛,直接将这个方程组转换为矩阵乘法(线性代数基础)。
可以得到:
( d p [ 2 ] [ 1 ] d p [ 2 ] [ 2 ] d p [ 2 ] [ 3 ] d p [ 2 ] [ 4 ] d p [ 2 ] [ 5 ] d p [ 2 ] [ 6 ] ) = ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 ) ( d p [ 1 ] [ 1 ] d p [ 1 ] [ 2 ] d p [ 1 ] [ 3 ] d p [ 1 ] [ 4 ] d p [ 1 ] [ 5 ] d p [ 1 ] [ 6 ] ) \left( \begin{matrix} dp[2][1] \\ dp[2][2] \\ dp[2][3] \\ dp[2][4] \\ dp[2][5] \\ dp[2][6] \\ \end{matrix} \right) = \left( \begin{matrix} 1 & 1 & 1 & 1 & 1& 1 \\ 1 & 1 & 1 & 1 & 1& 1 \\ 1 & 1 & 1 & 1 & 1& 1 \\ 1 & 0 & 1 & 1 & 1& 1 \\ 0 & 1 & 1 & 1 & 1& 1 \\ 1 & 1 & 1 & 1 & 1& 1 \\ \end{matrix} \right) \left( \begin{matrix} dp[1][1] \\ dp[1][2] \\ dp[1][3] \\ dp[1][4] \\ dp[1][5] \\ dp[1][6] \\ \end{matrix} \right) ⎝⎜⎜⎜⎜⎜⎜⎛dp[2][1]dp[2][2]dp[2][3]dp[2][4]dp[2][5]dp[2][6]⎠⎟⎟⎟⎟⎟⎟⎞=⎝⎜⎜⎜⎜⎜⎜⎛111101111011111111111111111111111111⎠⎟⎟⎟⎟⎟⎟⎞⎝⎜⎜⎜⎜⎜⎜⎛dp[1][1]dp[1][2]dp[1][3]dp[1][4]dp[1][5]dp[1][6]⎠⎟⎟⎟⎟⎟⎟⎞
把数值代入得到:
( 6 6 6 5 5 6 ) = ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 ) ( 1 1 1 1 1 1 ) \left( \begin{matrix} 6 \\ 6\\ 6\\ 5 \\ 5\\ 6 \\ \end{matrix} \right) = \left( \begin{matrix} 1 & 1 & 1 & 1 & 1& 1 \\ 1 & 1 & 1 & 1 & 1& 1 \\ 1 & 1 & 1 & 1 & 1& 1 \\ 1 & 0 & 1 & 1 & 1& 1 \\ 0 & 1 & 1 & 1 & 1& 1 \\ 1 & 1 & 1 & 1 & 1& 1 \\ \end{matrix} \right) \left( \begin{matrix} 1\\ 1 \\ 1 \\ 1\\ 1 \\ 1\\ \end{matrix} \right) ⎝⎜⎜⎜⎜⎜⎜⎛666556⎠⎟⎟⎟⎟⎟⎟⎞=⎝⎜⎜⎜⎜⎜⎜⎛111101111011111111111111111111111111⎠⎟⎟⎟⎟⎟⎟⎞⎝⎜⎜⎜⎜⎜⎜⎛111111⎠⎟⎟⎟⎟⎟⎟⎞
递推公式为:
( d p [ i ] [ 1 ] d p [ i ] [ 2 ] d p [ i ] [ 3 ] d p [ i ] [ 4 ] d p [ i ] [ 5 ] d p [ i ] [ 6 ] ) = ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 ) ( d p [ i − 1 ] [ 1 ] d p [ i − 1 ] [ 2 ] d p [ i − 1 ] [ 3 ] d p [ i − 1 ] [ 4 ] d p [ i − 1 ] [ 5 ] d p [ i − 1 ] [ 6 ] ) \left( \begin{matrix} dp[i][1] \\ dp[i][2] \\ dp[i][3] \\ dp[i][4] \\ dp[i][5] \\ dp[i][6] \\ \end{matrix} \right) = \left( \begin{matrix} 1 & 1 & 1 & 1 & 1& 1 \\ 1 & 1 & 1 & 1 & 1& 1 \\ 1 & 1 & 1 & 1 & 1& 1 \\ 1 & 0 & 1 & 1 & 1& 1 \\ 0 & 1 & 1 & 1 & 1& 1 \\ 1 & 1 & 1 & 1 & 1& 1 \\ \end{matrix} \right) \left( \begin{matrix} dp[i-1][1] \\ dp[i-1][2] \\ dp[i-1][3] \\ dp[i-1][4] \\ dp[i-1][5] \\ dp[i-1][6] \\ \end{matrix} \right) ⎝⎜⎜⎜⎜⎜⎜⎛dp[i][1]dp[i][2]dp[i][3]dp[i][4]dp[i][5]dp[i][6]⎠⎟⎟⎟⎟⎟⎟⎞=⎝⎜⎜⎜⎜⎜⎜⎛111101111011111111111111111111111111⎠⎟⎟⎟⎟⎟⎟⎞⎝⎜⎜⎜⎜⎜⎜⎛dp[i−1][1]dp[i−1][2]dp[i−1][3]dp[i−1][4]dp[i−1][5]dp[i−1][6]⎠⎟⎟⎟⎟⎟⎟⎞
由 X 1 X_1 X1推出 X n X_n Xn并不是件难事:
( d p [ n ] [ 1 ] d p [ n ] [ 2 ] d p [ n ] [ 3 ] d p [ n ] [ 4 ] d p [ n ] [ 5 ] d p [ n ] [ 6 ] ) = ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 ) n − 1 ( d p [ 1 ] [ 1 ] d p [ 1 ] [ 2 ] d p [ 1 ] [ 3 ] d p [ 1 ] [ 4 ] d p [ 1 ] [ 5 ] d p [ 1 ] [ 6 ] ) \left( \begin{matrix} dp[n][1] \\ dp[n][2] \\ dp[n][3] \\ dp[n][4] \\ dp[n][5] \\ dp[n][6] \\ \end{matrix} \right) = \left( \begin{matrix} 1 & 1 & 1 & 1 & 1& 1 \\ 1 & 1 & 1 & 1 & 1& 1 \\ 1 & 1 & 1 & 1 & 1& 1 \\ 1 & 0 & 1 & 1 & 1& 1 \\ 0 & 1 & 1 & 1 & 1& 1 \\ 1 & 1 & 1 & 1 & 1& 1 \\ \end{matrix} \right)^{n-1} \left( \begin{matrix} dp[1][1] \\ dp[1][2] \\ dp[1][3] \\ dp[1][4] \\ dp[1][5] \\ dp[1][6] \\ \end{matrix} \right) ⎝⎜⎜⎜⎜⎜⎜⎛dp[n][1]dp[n][2]dp[n][3]dp[n][4]dp[n][5]dp[n][6]⎠⎟⎟⎟⎟⎟⎟⎞=⎝⎜⎜⎜⎜⎜⎜⎛111101111011111111111111111111111111⎠⎟⎟⎟⎟⎟⎟⎞n−1⎝⎜⎜⎜⎜⎜⎜⎛dp[1][1]dp[1][2]dp[1][3]dp[1][4]dp[1][5]dp[1][6]⎠⎟⎟⎟⎟⎟⎟⎞
由此,我们发现可以使用矩阵快速幂了。
最后的结果是什么呢?
首先将dp[n][i]
求和,再乘以4^n
就是结果。
发现这样有点笨,反正矩阵快速幂是进行快速幂计算,4^n
也是进行快速幂计算,那将4^n
的计算也放在矩阵快速幂中计算不就好了嘛。
我们将 X 1 X_1 X1改为 ( 4 4 4 4 4 4 ) \left(\begin{matrix}4 \\4 \\4 \\4 \\4 \\4 \\\end{matrix}\right) ⎝⎜⎜⎜⎜⎜⎜⎛444444⎠⎟⎟⎟⎟⎟⎟⎞,再将系数矩阵 A A A之前填1
的地方改为4
,这样就实现了4^n
一起算了。
( a n s [ n ] [ 1 ] a n s [ n ] [ 2 ] a n s [ n ] [ 3 ] a n s [ n ] [ 4 ] a n s [ n ] [ 5 ] a n s [ n ] [ 6 ] ) = ( 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 0 4 4 4 4 0 4 4 4 4 4 4 4 4 4 4 4 ) n − 1 ( 4 4 4 4 4 4 ) \left( \begin{matrix} ans[n][1] \\ ans[n][2] \\ ans[n][3] \\ ans[n][4] \\ ans[n][5] \\ ans[n][6] \\ \end{matrix} \right) = \left( \begin{matrix} 4 & 4 & 4 & 4 & 4& 4 \\ 4 & 4 & 4 & 4 & 4& 4 \\ 4 & 4 & 4 & 4 & 4& 4 \\ 4 & 0 & 4 & 4 & 4& 4 \\ 0 & 4 & 4 & 4 & 4& 4 \\ 4 & 4 & 4 & 4 & 4& 4 \\ \end{matrix} \right)^{n-1} \left( \begin{matrix} 4 \\ 4 \\ 4 \\ 4 \\ 4 \\ 4 \\ \end{matrix} \right) ⎝⎜⎜⎜⎜⎜⎜⎛ans[n][1]ans[n][2]ans[n][3]ans[n][4]ans[n][5]ans[n][6]⎠⎟⎟⎟⎟⎟⎟⎞=⎝⎜⎜⎜⎜⎜⎜⎛444404444044444444444444444444444444⎠⎟⎟⎟⎟⎟⎟⎞n−1⎝⎜⎜⎜⎜⎜⎜⎛444444⎠⎟⎟⎟⎟⎟⎟⎞
进一步思考。
上面的系数矩阵 A A A是以第n
个矩阵上面点数为1~6
表示算出的方案数,那如果想用下面点数表示,系数矩阵又变成了什么样?
还是根据矩阵的定义和转移方程的含义用4
和0
填充系数矩阵,也可以像上面那样列出每一个情况的转移方程,再将方程组转换为矩阵的表达形式。
还是以样例为例,如果是以每个骰子下面点数来计算方案数,则转移方程的矩阵表达为:
( 5 5 6 6 6 6 ) = ( 4 4 4 4 0 4 4 4 4 0 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 ) ( 4 4 4 4 4 4 ) \left( \begin{matrix} 5 \\ 5 \\ 6 \\ 6 \\ 6\\ 6 \\ \end{matrix} \right) = \left( \begin{matrix} 4 & 4 & 4 & 4 & 0& 4 \\ 4 & 4 & 4 & 0 & 4& 4 \\ 4 & 4 & 4 & 4 & 4& 4 \\ 4 & 4 & 4 & 4 & 4& 4 \\ 4 & 4 & 4 & 4 & 4& 4 \\ 4 & 4 & 4 & 4 & 4& 4 \\ \end{matrix} \right) \left( \begin{matrix} 4 \\ 4 \\ 4 \\ 4 \\ 4 \\ 4 \\ \end{matrix} \right) ⎝⎜⎜⎜⎜⎜⎜⎛556666⎠⎟⎟⎟⎟⎟⎟⎞=⎝⎜⎜⎜⎜⎜⎜⎛444444444444444444404444044444444444⎠⎟⎟⎟⎟⎟⎟⎞⎝⎜⎜⎜⎜⎜⎜⎛444444⎠⎟⎟⎟⎟⎟⎟⎞
由 X 1 X_1 X1推出 X n X_n Xn:
( a n s [ n ] [ 1 ] a n s [ n ] [ 2 ] a n s [ n ] [ 3 ] a n s [ n ] [ 4 ] a n s [ n ] [ 5 ] a n s [ n ] [ 6 ] ) = ( 4 4 4 4 0 4 4 4 4 0 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 ) n − 1 ( 4 4 4 4 4 4 ) \left( \begin{matrix} ans[n][1] \\ ans[n][2] \\ ans[n][3] \\ ans[n][4] \\ ans[n][5] \\ ans[n][6] \\ \end{matrix} \right) = \left( \begin{matrix} 4 & 4 & 4 & 4 & 0& 4 \\ 4 & 4 & 4 & 0 & 4& 4 \\ 4 & 4 & 4 & 4 & 4& 4 \\ 4 & 4 & 4 & 4 & 4& 4 \\ 4 & 4 & 4 & 4 & 4& 4 \\ 4 & 4 & 4 & 4 & 4& 4 \\ \end{matrix} \right)^{n-1} \left( \begin{matrix} 4 \\ 4 \\ 4 \\ 4 \\ 4 \\ 4 \\ \end{matrix} \right) ⎝⎜⎜⎜⎜⎜⎜⎛ans[n][1]ans[n][2]ans[n][3]ans[n][4]ans[n][5]ans[n][6]⎠⎟⎟⎟⎟⎟⎟⎞=⎝⎜⎜⎜⎜⎜⎜⎛444444444444444444404444044444444444⎠⎟⎟⎟⎟⎟⎟⎞n−1⎝⎜⎜⎜⎜⎜⎜⎛444444⎠⎟⎟⎟⎟⎟⎟⎞
总结一下,我们到底如何根据输入的排斥点对,来确定系数矩阵的哪些位置为0
。
假设排斥点对为 {a, b}
。
如果是以上面点数表示的方案数,则应该将矩阵的第a的反面
行第b
列和第b的反面
行第a
列设置为0
,其余位置设置为4
;
如果是以下面点数表示的方案数,则应该将矩阵的第a
行第b的反面
列和第b
行第a的反面
列设置为0
,其余位置设置为4
.
无论哪种方式最后计算的结果都一样。
(建议自己理解一下两种方式如此设置的原因,还是根据矩阵的定义和转移方程的含义理解)
再就是自己实现一下代码了,数据结构的设计比较重要(我就是因为数据结构定义的很拉跨所以debug都费劲)
我不理解为什么归为“简单”??????????
// 78%
#include
using namespace std;
const int MOD = 1e9+7;
typedef long long ll;
int op[7] = {0, 4, 5, 6, 1, 2, 3}; // op[1]=4, op[2]=5, op[3]=6, op[4]=1, op[5]=2, op[6]=3
int n, m, a, b;
ll dp[2][7]; // dp[i][j]表示第i个骰子的上面点数为j的情况下,底下的i个骰子的方案数
// dp采用滚动数组的方式保存
ll c = 4; // 初始设为4,因为下面循环从第二个骰子开始,c的初始值为第一个骰子的可能数。
ll ans;
bool duili[7][7];
int main()
{
memset (duili, false, sizeof duili);
cin >> n >> m;
for (int i = 1;i <= m;i ++) {
cin >> a >> b;
duili[a][b] = duili[b][a] = true; // 这个表示方法没想到
}
for (int i = 1;i <= 6;i ++) dp[1][i] = 1; // 初始化,当只有一个骰子时,上面点数为i的情况只有一种(不考虑旋转)
for (int i = 2;i <= n;i ++) {
c = (c * 4) % MOD;
for (int j = 1;j <= 6;j ++) { // 第i个骰子的上面点数为j
dp[i&1][j] = 0; // 使用滚动数组时如果后面要进行累加,一定要清空!!!
for (int k = 1;k <= 6;k ++) { // 枚举第i-1个骰子上面点数k
if (duili[op[j]][k]) continue; // 如果不可紧贴
dp[i&1][j] = (dp[i&1][j] + dp[(i-1)&1][k]) % MOD;
}
}
}
for (int i = 1;i <= 6;i ++) ans += dp[n&1][i], ans %= MOD;
cout << c * ans % MOD << endl;
}
#include
using namespace std;
typedef long long ll;
const ll MOD = 1e9+7;
ll n, m;
int a, b;
int opp[7] = {0, 4, 5, 6, 1, 2, 3};
struct Matrix {
ll m[10][10];
int row, col;
Matrix (int r, int c, int fill) { // 全 fill 矩阵
row = r, col = c;
for (int i = 1;i <= r;i ++)
for (int j = 1;j <= c;j ++)
m[i][j] = fill;
}
Matrix (int r) { // 单位矩阵 E
row = r, col = r;
memset (m, 0, sizeof m);
for (int i = 1;i <= r;i ++)
m[i][i] = 1;
}
ll Sum () {
ll res = 0;
for (int i = 1;i <= row;i ++)
for (int j = 1;j <= col;j ++)
res = (res + m[i][j]) % MOD;
return res;
}
void print () {
for (int i = 1;i <= row;i ++, cout << endl)
for (int j = 1;j <= col;j ++)
cout << m[i][j] << ' ';
}
};
Matrix Matrix_Mul (Matrix a, Matrix b) {
Matrix c = Matrix(a.row, b.col, 0);
for (int i = 1;i <= a.row;i ++)
for (int j = 1;j <= b.col;j ++)
for (int k = 1;k <= a.col;k ++)
c.m[i][j] = (c.m[i][j] + a.m[i][k] * b.m[k][j] % MOD) % MOD;
return c;
}
Matrix KSM (Matrix matrix, ll p) {
Matrix res = Matrix (6); // E:6 ×6
while (p) {
if (p & 1) res = Matrix_Mul (res, matrix);
matrix = Matrix_Mul (matrix, matrix);
p >>= 1;
}
return res;
}
int main()
{
cin >> n >> m;
Matrix T = Matrix (6, 6, 4);
Matrix A = Matrix (6, 1, 4);
while (m -- ) {
cin >> a >> b;
T.m[opp[a]][b] = T.m[opp[b]][a] = 0; // 上面
// T.m[b][opp[a]] = T.m[a][opp[b]] = 0; // 下面
}
// T.print();
Matrix T_pow = KSM (T, n-1);
cout << Matrix_Mul (T_pow, A).Sum() << endl;
return 0;
}