在网上看了一些答案,大部分都没有AC,
题目不算难,但是不好理解,想通之后就很好做了,
想了大半天之后,终于做了出来,分享一下我的理解。。。。
大家可以在这个网站上提交,看下自己敲的对不对:https://www.dotcpp.com/oj/problem2261.html
题目:
垒骰子赌圣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
思路:
① 建立一个冲突矩阵Conflict[i][j],表示 第i面 和 第j面的背面 冲突,至于为什么要这样,举个例子:
比如题目中的例子, Conflict[1][5] 和 Conflict[2][4] 设成0,
代表 当第一层的骰子,1朝上的时候,那么第二层骰子,5就不能朝上(2的背面),不然的话1和2就紧贴了。
② 建立一个Count[j]矩阵,记录当前某高度下的各个面朝上的总方案数,当然刚开始的时候Count[1]=Count[2]=···=Count[6]=1,因为第一层顶层可以是任意一面。
③ 现在Conflict 乘 Count ,可以得到第二层 各个面朝上 的总方案数。
乘完以后,Count里面,第一个5的意思是,如果第一层的顶面是1,那第二层的顶面有5种摆放方式(因为5不能朝上)。
然后每个面的总方案数加起来5+5+6+6+6+6 = 34,就是垒骰子总方案数了。
④ 如果要得到第三层 各个面朝上的总方案数,只需要Cnflict 乘以 第二层的count矩阵;
⑤ 那么现在得出结论,
要知道第2层 各个面朝上的总方案数,只需要计算 Cnflict * Count
要知道第3层 各个面朝上的总方案数,只需要计算 Cnflict * Cnflict * Count
以此类推,
要知道第N层 各个面朝上的总方案数, 只需要计算 Cnflict * Cnflict * ··· * Cnflict * Count N-1 个Cnflict相乘
⑥最后的count每项加起来,然后乘以,因为我们只是计算的竖直方向不冲突的方案,骰子的4个侧面可以随便朝向,总共有n个骰子,所以最后结果要乘以4的n次方。
#include <iostream>
#include <cstring>
#define ll long long
using namespace std;
const ll MOD = 1e9 + 7;
int back[] = {0, 4, 5, 6, 1, 2, 3};
struct Matrix
{
ll v[7][7];
};
Matrix mul(Matrix A, Matrix B)
{
Matrix C;
for (int i = 1; i <= 6; i++)
for (int j = 1; j <= 6; j++)
{
C.v[i][j] = 0;
for (int k = 1; k <= 6; k++)
{
C.v[i][j] += ((A.v[i][k] % MOD) * (B.v[k][j] % MOD)) % MOD;
C.v[i][j] %= MOD;
}
}
return C;
}
Matrix pow(Matrix A, ll k)
{
Matrix ans;
for (int i = 1; i <= 6; i++)
for (int j = 1; j <= 6; j++)
if (i == j)
ans.v[i][j] = 1;
else
ans.v[i][j] = 0;
while (k)
{
if (k & 1)
ans = mul(ans, A);
A = mul(A, A);
k >>= 1;
}
return ans;
}
ll pow2(ll num, ll k)
{
int ans = 1;
while (k)
{
if (k & 1)
ans = ans * num % MOD;
num = num * num % MOD;
k >>= 1;
}
return ans % MOD;
}
int main()
{
Matrix Conflict;
for (int i = 1; i <= 6; i++)
for (int j = 1; j <= 6; j++)
Conflict.v[i][j] = 1;
ll n;
int m, a, b;
cin >> n >> m;
while (m--)
{
cin >> a >> b;
Conflict.v[a][back[b]] = 0;
Conflict.v[b][back[a]] = 0;
}
Conflict = pow(Conflict, n - 1);
ll sum = 0;
for (int i = 1; i <= 6; i++)
for (int j = 1; j <= 6; j++)
{
sum += Conflict.v[i][j] % MOD;
sum %= MOD;
}
sum = (sum * pow2(4, n)) % MOD;
cout << sum << endl;
system("pause");
return 0;
}