对于 100% 的数据:0 < n <= 10^9, m <= 36
分析:
考虑最低一层,每个面都可以朝上,此时每个面朝上的情况都是1。考虑第二层的时候,我们假设面1 和面2不能互相接触,也就是说,前一层面1朝上和当前层面5朝上的情况不能发生,同理,前一层面2朝上跟当前层面4朝上的情况也不能发生。我们用一个数组来记录这种情况。我们可以发现,每一层的数目都只与前一层的数目有关。用dp就可以解决这个题目,但还不够快,我们可以用线性代数的知识,利用矩阵快速幂进行优化。
6乘6的转移矩阵a[i][j],a[i][j]=1表示当前层以i为顶面跟前一层以j为顶面不冲突,反之则冲突。1乘6基础矩阵的b[i]表示以i为顶面的情况数
#include
using namespace std;
typedef long long ll;
struct matrix
{
int n, m;
ll a[7][7];
};
int fro[7] = {0, 4, 5, 6, 1, 2, 3};
matrix matrix_mul(matrix A, matrix B, int mod)
{
matrix C;
C.n = A.n;
C.m = B.m;
for(int i = 1; i <= A.n; i++)
for(int j = 1; j <= B.m; j++)
{
C.a[i][j] = 0;
for(int k = 1; k <= A.m; k++)
{
C.a[i][j] += (A.a[i][j]*B.a[k][j] % mod);
}
}
return C;
}
matrix unit()
{
matrix res;
res.n = 6;
res.m = 6;
for(int i = 1; i <= res.n; i++)
for(int j = 1; j <= res.m; j++)
if(i == j)
res.a[i][j] = 1;
else
res.a[i][j] = 0;
return res;
}
matrix matrix_pow(matrix A, int n, int mod)
{
matrix res = unit(), temp = A;
for(; n; n /= 2)
{
if(n&1)
res = matrix_mul(res, temp, mod);
temp = matrix_mul(temp, temp, mod);
}
return res;
}
ll pow_mod(ll a, int n, int mod)
{
ll res = 1, temp = a;
for(; n; n/=2)
{
if(n&1)
res = res*temp%mod;
temp = temp*temp%mod;
}
return res;
}
int main()
{
int m, u, v;
ll ans = 0, n;
scanf("%lld%d", &n, &m);
matrix col;
col.n = 6;
col.m = 6;
for(int i = 0; i < 7; i++)
for(int j = 0; j < 7; j++)
col.a[i][j] = 1;
for(int i = 0; i < m; i++)
{
scanf("%d%d", &u, &v);
col.a[fro[u]][v] = 0;
col.a[fro[v]][u] = 0;
}
matrix res, base;
for(int i = 1; i <= 6; i++)
base.a[1][i] = 1;
base.n = 1;
base.m = 6;
int MOD = 1e9+7;
res = matrix_pow(col, n-1, MOD);
res = matrix_mul(base, res, MOD);
for(int i = 1; i <= 6; i++)
ans = (ans + res.a[1][i]) % MOD;
ans = ans * pow_mod(4, n, MOD) % MOD;
printf("%lld\n", ans);
return 0;
}