解题思路:动态转移方程,先考虑底面应该是挺好想的,放第n个骰子,可以由n-1个骰子推出,为了方便将他的冲突面,改成都是朝向的那个面,比如1 2 冲突,那对应的两个骰子的底面是1,5;第n个骰子底面是1,可能第n-1骰子底面是1~6,这样的话,就可能有36种转移,当然最后要乘以4*n,因为我们只考虑了底面,但是题目的n有1e9,我们不能直接for循环。这里需要矩阵快速幂,
An=An-1*X X是一个六阶矩阵,Xij=1代表可以i面j面这样叠着放(对应的都是朝下的那个面),反之则不可。
#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define fi first
#define se second
#define ms(_data,v) memset(_data,v,sizeof(_data))
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int mod=1e9+7;
int n,m,pd[10];
void init(){
pd[1]=4,pd[4]=1;
pd[2]=5,pd[5]=2;
pd[3]=6,pd[6]=3;
}
struct matrix{
int m[7][7];
matrix(){ms(m,0);}
matrix operator *(const matrix &tp)const{
matrix res;
for(int i=1;i<=6;++i){
for(int j=1;j<=6;++j){
for(int k=1;k<=6;++k){
res.m[i][j]=(res.m[i][j]+m[i][k]*tp.m[k][j])%mod;
}
}
}
return res;
}
};
matrix matpow(matrix x,int n){
matrix ans;
for(int i=1;i<=6;++i) ans.m[i][i]=1;
while(n){
if(n&1) ans=ans*x;
x=x*x;
n>>=1;
}
return ans;
}
ll mpow(int x,int n){
ll ans=1;
while(n){
if(n&1) ans=(ans*x)%mod;
x=(x*x)%mod;
n>>=1;
}
return ans;
}
int main(){
std::ios::sync_with_stdio(0);
init();
cin>>n>>m;
int x,y;
matrix a;
for(int i=1;i<=6;++i)
for(int j=1;j<=6;++j) a.m[i][j]=1;
for(int i=0;i<m;++i){
cin>>x>>y;
a.m[x][pd[y]]=0;
a.m[y][pd[x]]=0;
}
matrix ta=matpow(a,n-1);
ll t=pow(4,n);
ll res=0;
for(int i=1;i<=6;++i){
for(int j=1;j<=6;++j){
res=(res+ta.m[i][j])%mod;
}
}
cout<<(t*res)%mod<<endl;
return 0;
}