蓝桥杯 15省赛 C10 垒骰子(dp数组)
程序员文章站
2022-07-13 23:53:34
...
蓝桥杯 15省赛 C10 垒骰子(dp数组)
垒骰子
赌圣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
思路:
经典动态规划,马上想到dp数组
总结:
向热心大佬学习了一波 快速幂
public class 垒骰子_动态dp_10 {
static int MOD =1000000007; //由于计算过程中使用大数->需要多次取模,故声明变量;
static int[] numb = {-1 ,4 ,5 ,6 ,1 ,2 ,3}; //骰子接触面刚好是相对面,故不用直接用for循环变量
static boolean[][] conf =new boolean[7][7]; //冲突
static int n ,m; //输入(骰子数 冲突数)
public static void main(String[] args) {
init();
BigInteger[][] dp =new BigInteger[2][7]; //骰子数目可能很大,并且重复单位为2的组合(控制空间消耗),故使用大数的滚动dp数组
int index =0; //设置滚动数组的层指针
//第一层骰子 后面就是在不冲突的对面情况下,将这个'1'一次次累加
for(int i =1 ;i <=6 ;i ++) {dp[index][i] =BigInteger.ONE;}
//第二层骰子
for(int i =2 ;i <=n ;i ++) {
index =1 -index; //层指针滚动到另一层
for(int j =1 ;j <=6 ;j ++) {
dp[index][j] =BigInteger.ZERO; //清空这一层数组的当前位置的值
for(int k =1 ;k <=6 ;k ++) {
if(!conf[numb[j]][k]) { //上一层的这个面是否和这一层的这个面的对面冲突
dp[index][j] =dp[index][j].add(dp[1 -index][k]).mod(new BigInteger(MOD +""));
//每次计算尽量取模,防止数超出范围(取模运算跟乘法一样,可以分配的)
}
}
}
}
//累加各个面的可能情况
BigInteger sum =BigInteger.ZERO;
for(int i =1 ;i <=6 ;i ++) {
sum =sum.add(dp[index][i]).mod(new BigInteger(MOD +""));
}
System.out.println(sum.multiply(quickPow(4 ,n)).mod(new BigInteger(MOD +"")));
//侧面有4种朝向,故对'4'取幂
}
//快速幂
private static BigInteger quickPow(int x, int y) {
BigInteger ans =BigInteger.ONE;
BigInteger base =new BigInteger(x +""); //当前底数(不是这里的'x',会累积的)
while(y !=0) {
if((y &1) ==1) {
//指数的二进制的末位是'1'的话,乘上当前权值(权值:底数的当前指数次方)
ans =ans.multiply(base).mod(new BigInteger(MOD +""));
}
base =base.multiply(base).mod(new BigInteger(MOD +""));//底数
y >>=1;//指数右移(不是减一)
}
return ans;
}
private static void init() {
Scanner sc =new Scanner(System.in);
n =sc.nextInt();
m =sc.nextInt();
for(int i =0 ;i <m ;i ++) {
int a =sc.nextInt();
int b =sc.nextInt();
conf[b][a] =conf[a][b] =true;
}
sc.close();
}
}