蓝桥杯---垒骰子

文章讲述了如何通过暴力递归和动态规划方法计算在给定互斥规则下的不同垒骰子方式,输出结果对10^9+7取模。
摘要由CSDN通过智能技术生成

赌圣atm晚年迷恋上了垒骰子,就是把骰子一个垒在另一个上边,不能歪歪扭扭,要垒成方柱体。经过长期观察,atm 发现了稳定骰子的奥秘:有些数字的面贴着会互相排斥!我们先来规范一下骰子:1的对面是4,2的对面是5,3 的对面是 6。假设有 m 组互斥现象,每组中的那两个数字的面紧贴在一起,骰子就不能稳定的垒起来。atm想计算一下有多少种不同的可能的垒骰子方式。

两种垒骰子方式相同,当且仅当这两种方式中对应高度的骰子的对应数字的朝向都相同。由于方案数可能过多,请输出模 10^9+7的结果。不要小看了 atm的骰子数量哦~

[输入格式]
第一行两个整数 n m
 接下来 :n表示骰子数目
                m 行,每行两个整数ab,表示 a 和b 不能紧贴在一起。

[输出格式]
一行一个数,表示答案模 10^9+7的结果。

[样例输入]
2 1

1 2

[样例输出]
544

[数据范围]
对于 30% 的数据:n <= 5
对于 60% 的数据:n <= 100
对于 100% 的数据:0 <n <= 10^9,m <= 36

思路:暴力递归、动态规划

代码

public class _09垒骰子 {
    static int op[] = new int [7];
    private static int n;
    private static int m;
    private static final long MOO=1000000007;

    static void init(){
        op[1] = 4;
        op[4] = 1;
        op[2] = 5;
        op[5] = 2;
        op[3] = 6;
        op[6] = 3;
    }
    public static void main(String[] args) {
        init();
        Scanner input = new Scanner(System.in);
        n = input.nextInt();
        m = input.nextInt();
        long conflict[][] = new long[6][6];
        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 6; j++) {
                conflict[i][j] = 1;
            }
        }

//        建立冲突矩阵
        for (int i = 0; i < m; i++) {
            int a = input.nextInt();
            int b = input.nextInt();
            conflict[op[a-1]][b-1] = 0;
            conflict[op[b-1]][a-1] = 0;
        }
//        求冲突矩阵的n-1次方
        long[][] nPow_n_1 = mPow(conflict,n-1);
        //            累加矩阵的每个元素
        long ans = 0;
        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 6; j++) {
                ans = (ans + nPow_n_1[i][j])%MOO;
            }
        }
//            ans*4^n
        System.out.println(ans * power(4,n)%MOO);
    }
    private static long power(long i,int n){
        int ans = 1;
        while(n != 0){
            if((n & 1) ==1){
                ans *= (ans * i)%MOO;
            }
            i = i*i%MOO;
            n >>= 1;
        }
        return ans;
    }
//    矩阵的快速幂
    private static long[][] mPow(long[][] conflict,int n){
        long[][] e = new long[6][6];
        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 6; j++) {
                if(i == j){
                    e[i][j] = 1;
                }else{
                    e[i][j] = 0;
                }
            }
        }
        while (n != 0){
            if((n & 1) == 1){
                e = mMul(e,conflict);
            }
            conflict = mMul(conflict,conflict);
            n >>= 1;
        }
        return e;
    }
    private static long[][] mMul(long[][] a ,long[][] b){
        long[][] ans = new long[6][6];
        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 6; j++) {
                for (int k = 0; k < 6; k++) {
                    ans[i][j] = (ans[i][j]+a[i][k] * b[k][j])%MOO;
                }
            }
        }
        return ans;
    }
}

 效果

  • 15
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯狂小羊啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值