垒骰子(15年蓝桥杯A组第九题)
约 1229 字大约 4 分钟
2020-07-23
赌圣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
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。 注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。 注意:主类的名字必须是:Main,否则按无效代码处理。
递归 (超时)
import java.util.Scanner;
public class Main {
private static final int MOD = 1000000007;
private static int[] op = { 0, 4, 5, 6, 1, 2, 3 };
private static boolean[][] bool;
public static void main(String[] args) {
bool = new boolean[7][7];
Scanner sr = new Scanner(System.in);
int n = sr.nextInt();
int m = sr.nextInt();
while (m-- > 0) {
int x = sr.nextInt();
int y = sr.nextInt();
bool[x][y] = bool[y][x] = true;
}
sr.close();
int count = 0;
for (int i = 1; i <= 6; i++) {
// f(n - 1, i) << 2 旋转 每一个骰子4种情况
count = (count + (f(n - 1, i) << 2)) % MOD;
}
System.out.println(count);
}
private static int f(int n, int up) {
if (n == 0) return 1;
int count = 0;
for (int i = 1; i <= 6; i++) {
if (bool[op[up]][i])
continue;
count = (count + (f(n - 1, i) << 2)) % MOD;
}
return count;
}
}
DP (超时)
import java.util.Scanner;
public class Main {
private static final int MOD = 1000000007;
private static int[] op = { 0, 4, 5, 6, 1, 2, 3 };
private static boolean[][] bool;
public static void main(String[] args) {
bool = new boolean[7][7];
Scanner sr = new Scanner(System.in);
int n = sr.nextInt();
int m = sr.nextInt();
while (m-- > 0) {
int x = sr.nextInt();
int y = sr.nextInt();
bool[x][y] = bool[y][x] = true;
}
sr.close();
// dp[i][j] 表示第i层j朝上的方案数
// 滚动数组
int[][] dp = new int[2][7];
for (int i = 1; i <= 6; i++)
dp[0][i] = 1;
int cur = 0;
for (int i = 2; i <= n; i++) {
cur = 1 - cur;
for (int j = 1; j <= 6; j++) {
for (int k = 1; k <= 6; k++) {
// 判断是否冲突
if (bool[op[j]][k]) continue;
// 累加上一个骰子所有不冲突的方案数 就是当前垒骰子的方案数
dp[cur][j] = (dp[cur][j] + dp[1 - cur][k]) % MOD;
}
}
}
int count = 0;
for (int i = 1; i <= 6; i++)
count = (count + dp[cur][i]) % MOD;
// pow(4, n) 所有骰子旋转的方案数
System.out.println(count * pow(4, n) % MOD);
}
// 快速幂
private static int pow(int x, int y) {
int results = 1;
while (y > 0) {
if ((y & 1) == 1) {
results = results * x % MOD;
}
x = x * x % MOD;
y >>= 1;
}
return results;
}
}
矩阵快速幂
F1表示1-6 每一个面朝上的方案数
import java.util.Scanner;
public class Main {
private static final long MOD = 1000000007;
private static int[] op = { 0, 4, 5, 6, 1, 2, 3 };
public static void main(String[] args) {
Scanner sr = new Scanner(System.in);
int n = sr.nextInt();
int m = sr.nextInt();
long[][] matrixT = initMatrix(6, 1);
while (m-- > 0) {
int x = sr.nextInt();
int y = sr.nextInt();
// 建立冲突矩阵 0为冲突
matrixT[op[x] - 1][y - 1] = matrixT[op[y] - 1][x - 1] = 0;
}
sr.close();
long[][] matrixTn = pow(matrixT, n - 1);
long count = 0;
for (int i = 0; i < 6; i++)
for (int j = 0; j < 6; j++)
count = (count + matrixTn[i][j]) % MOD;
System.out.println((count * pow(4, n)) % MOD);
}
// 创建单位矩阵
private static long[][] initUnitMatrix(int n) {
long[][] matrix = new long[n][n];
for (int i = 0; i < n; i++)
matrix[i][i] = 1;
return matrix;
}
// 创建矩阵 并初始化为x
private static long[][] initMatrix(int n, long x) {
long[][] matrix = new long[n][n];
if (x != 0)
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
matrix[i][j] = x;
return matrix;
}
// 矩阵乘法
private static long[][] multiplication(long[][] results1, long[][] results2) {
long[][] results = initMatrix(6, 0);
for (int i = 0; i < 6; i++)
for (int j = 0; j < 6; j++)
for (int k = 0; k < 6; k++)
results[i][j] = (results[i][j] + results1[i][k] * results2[k][j]) % MOD;
return results;
}
// 矩阵快速幂
private static long[][] pow(long[][] matrix, long y) {
long[][] results = initUnitMatrix(6);
while (y > 0) {
if ((y & 1) == 1) {
results = multiplication(results, matrix);
}
matrix = multiplication(matrix, matrix);
y >>= 1;
}
return results;
}
// 快速幂
private static long pow(long x, long y) {
long results = 1;
while (y > 0) {
if ((y & 1) == 1) {
results = results * x % MOD;
}
x = x * x % MOD;
y >>= 1;
}
return results;
}
}