zoukankan      html  css  js  c++  java
  • java实现第六届蓝桥杯垒骰子

    垒骰子

    题目描述
    赌圣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,否则按无效代码处理。

    解法一:

    public class 垒骰子_9_滚动数组 {
    	private static int a[][] = new int[10][10];//存放6个面的排斥关系,只用到数组下标1~7
    	
    	private static int b[] = new int [7];//对立面
    	private static long count ;
    	private static long C = 1000000007;
    	
    	private static boolean check(int current,int last)
    	{
    		if(a[current][last]==1)//说明两个骰子互相排斥
    		{
    			return true;
    		}
    		return false;
    	}
    	
    	
    	
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		b[1]=4;b[4]=1;
    		b[2]=5;b[5]=2;
    		b[3]=6;b[6]=3;
    		int n,m,a1,a2;
    		Scanner in = new Scanner(System.in);
    		n = in.nextInt();
    		int num = 4;
    		m = in.nextInt();
    		for(int i = 0;i<m;i++)
    		{
    			a1 = in.nextInt();
    			a2 = in.nextInt();
    			a[a1][a2]=1;
    			a[a2][a1]=1;
    		}
    		//滚动数组
    		int dp[][] = new int[2][7];//dp[i][j]表示某一高度的骰子j面朝上的方案数
    		int e = 0;
    		for(int i=1;i<7;i++)
    		{
    			dp[e][i]=1;//初始化 已知高度为1的骰子的方案只有一种,此处忽略结果×4的情况,在下面加上
    		}
    		for(long i=2;i<=n;i++)//从第二颗骰子算,到第n颗
    		{
    			e = 1-e;
    			num = (int) ((num*4)%C);
    			for(int j = 1;j<7;j++)//遍历当前骰子各面
    			{
    				dp[e][j]=0;//初始化下一颗骰子j面朝上的方案数为0
    				
    				for(int k = 1;k<7;k++)//遍历之前一颗骰子的6个面
    				{
    					if(!check(k,b[j]))//不相互排斥,k为之前下方骰子的朝上面,b[j]为当前骰子朝上面的对立面,即朝下面
    					{
    						dp[e][j] += dp[1-e][k];
    					}
    				}
    				dp[e][j] = (int) (dp[e][j]%C);
    				
    			}
    		}
    		for(int i = 1;i<7;i++)
    		{
    			count += dp[e][i];
    			count = count%C;
    		}
    		count = (count*num)%C;//这个地方相乘后仍然很大,是这个算法的弊端
    		//count = quickPow(10,33,1000000007);
    		System.out.println(count);
    	}
    	
    	//整数快速幂,写在这里只是为了加强记忆,这个地方没用,为后续快速矩阵幂解法做铺垫
    	private static long quickPow(long count2,int n,long mod)
    	{
    		long res = count2;
    		long ans = 1;
    		while(n!=0)
    		{
    			if((n&1)==1)
    			{
    				ans = (ans*res)%mod;
    			}
    			res = (res*res)%mod;
    			n >>= 1;
    		}
    		return ans;
    	}
    }
    











    解法二:
    此篇java代码实现了快速矩阵幂来计算前n-1个6*6阶矩阵的乘积,最后的sum相当于传送门里博主的B矩阵求和,也就是最终没有乘4n的答案,这样就得到了第n个骰子各面朝上的所有情况,当然要记得最后乘个4n,在这里顺便也给出了整数快速幂的实现。

    public class 垒骰子_9_快速矩阵幂 {
    	private static int mod = 1000000007;
     
    	static class Matrix
    	{
    		int a[][]= new int [6][6];
    		
    		public Matrix(){}
    		
    		public Matrix(int x)//初始化对角线元素,以构造单位矩阵
    		{
    			for(int i = 0;i<6;i++)
    			{
    				for(int j=0;j<6;j++)
    				{
    					a[i][j]= 0;
    				}
    			}
    			for(int i = 0;i<6;i++)
    			{
    				a[i][i] = x;
    			}
    		}
    	}
    	
    	public static int q_pow(int m,int n,int mod)//计算m^n
    	{
    		int base = m;
    		int ans = 1;
    		while(n>0)
    		{
    			if((n&1)==1)
    				ans = (ans*base)%mod;
    			base = (base*base)%mod;
    			n>>=1;
    		}
    		return ans;
    	}
    	
    	public static Matrix mul(Matrix m1,Matrix m2)
    	{
    		Matrix m = new Matrix();
    		for(int i = 0;i<6;i++)
    		{
    			for(int j = 0;j<6;j++)
    			{
    				for(int k = 0;k<6;k++)
    				{
    					m.a[i][j] += (m1.a[i][k]*m2.a[k][j])%mod;
    				}
    			}
    		}
    		return m;
    	}
    	public static Matrix q_pow(Matrix m,int n)
    	{
    		Matrix ans = new Matrix(1);//这里要变成单位矩阵
    		Matrix base = m;
    		while(n>0)
    		{
    			if((n&1)==1)
    				ans = mul(ans,base);
    			base = mul(base,base);
    			n>>=1;
    		}
    		return ans;
    	}
    	
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		int n,m,a1,a2;
    		int sum = 0;
    		Scanner in = new Scanner(System.in);
    		n = in.nextInt();
    		int num;
    		m = in.nextInt();
    		Matrix matrix = new Matrix();
    		for(int i = 0;i<6;i++)
    		{
    			for(int j=0;j<6;j++)
    			{
    				matrix.a[i][j]= 1;
    			}
    		}
    		for(int i = 0;i<m;i++)
    		{
    			a1 = in.nextInt();
    			a2 = in.nextInt();
    			matrix.a[a1-1][a2-1]=0;
    			matrix.a[a2-1][a1-1]=0;
    		}
    		//快速矩阵幂运算
    		Matrix final_matrix = q_pow(matrix,n-1);
    		for(int i=0;i<6;i++)
    		{
    			for(int j=0;j<6;j++)
    			{
    				sum = (sum+final_matrix.a[i][j])%mod;
    			}
    		}
    		num = q_pow(4,n,mod);
    		System.out.println((sum*num)%mod);
    	}
     
    }
    
  • 相关阅读:
    Solution: Win 10 和 Ubuntu 16.04 LTS双系统, Win 10 不能从grub启动
    在Ubuntu上如何往fcitx里添加输入法
    LaTeX 笔记---Q&A
    Hong Kong Regional Online Preliminary 2016 C. Classrooms
    Codeforces 711E ZS and The Birthday Paradox
    poj 2342 anniversary party
    poj 1088 滑雪
    poj 2479 maximum sum
    poj 2481 cows
    poj 2352 stars
  • 原文地址:https://www.cnblogs.com/a1439775520/p/13077477.html
Copyright © 2011-2022 走看看